|
@@ -49,12 +49,8 @@ class KMBookmarkController: NSWindowController {
|
|
|
override func windowDidLoad() {
|
|
|
super.windowDidLoad()
|
|
|
setupToolbar()
|
|
|
-
|
|
|
-// outlineView.delegate = self
|
|
|
-// outlineView.dataSource = self
|
|
|
-// outlineView.registerForDraggedTypes([kPasteboardTypeBookmarkRows, .fileURL, .string])
|
|
|
-// bookmarkOutlineView.outlineView.doubleAction = #selector(doubleClickBookmark(_:))
|
|
|
-
|
|
|
+ bookmarkOutlineView.outlineView.menu = NSMenu()
|
|
|
+ bookmarkOutlineView.outlineView.menu?.delegate = self
|
|
|
|
|
|
bookmarkOutlineView.data = self.bookmarkRoot
|
|
|
bookmarkOutlineView.doubleClickAction = { [unowned self] view in
|
|
@@ -189,12 +185,14 @@ class KMBookmarkController: NSWindowController {
|
|
|
}
|
|
|
|
|
|
|
|
|
- func deleteBookmarks(bookmarks: [KMBookmark]) {
|
|
|
+ @objc 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)
|
|
|
}
|
|
|
bookmarkOutlineView.reloadData()
|
|
|
+
|
|
|
+ KMBookmarkManager.manager.saveData()
|
|
|
}
|
|
|
|
|
|
|
|
@@ -269,119 +267,38 @@ class KMBookmarkController: NSWindowController {
|
|
|
// statusBar.toggle(below: outlineView.enclosingScrollView, animate: sender != nil)
|
|
|
// }
|
|
|
//
|
|
|
-// func clickedBookmarks() -> [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? [KMBookmark] 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? [KMBookmark] 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
|
|
|
+ @IBAction func deleteMenuBookmarks(_ sender: Any) {
|
|
|
+ guard let items = clickedBookmarks() as? [KMBookmark] else { return }
|
|
|
+ self.deleteBookmarks(bookmarks: items)
|
|
|
+ }
|
|
|
+
|
|
|
+ @IBAction func openBookmarks(_ sender: Any) {
|
|
|
+ guard let items = clickedBookmarks() as? [KMBookmark] 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 {
|
|
|
+ let row = bookmarkOutlineView.outlineView.clickedRow
|
|
|
+ if row > 0 {
|
|
|
+ bookmarkOutlineView.outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
|
|
|
+ QLPreviewPanel.shared().makeKeyAndOrderFront(nil)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
-// func addItemForBookmark(_ bookmark: KMBookmark, 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? KMBookmark 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<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool { false }
|
|
|
-//
|
|
|
-// // MARK: - Toolbar
|
|
|
-//
|
|
|
+ func menuHasKeyEquivalent(_ menu: NSMenu, for event: NSEvent, target: AutoreleasingUnsafeMutablePointer<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ // MARK: - Toolbar
|
|
|
+
|
|
|
func setupToolbar() {
|
|
|
// Create a new toolbar instance, and attach it to our document window
|
|
|
let toolbar = NSToolbar(identifier: kBookmarksToolbarIdentifier)
|
|
@@ -508,315 +425,315 @@ class KMBookmarkController: NSWindowController {
|
|
|
|
|
|
}
|
|
|
|
|
|
-extension KMBookmarkController: NSOutlineViewDelegate, NSOutlineViewDataSource {
|
|
|
- //MARK: NSOutlineViewDataSource
|
|
|
-
|
|
|
- func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] {
|
|
|
- var lastBm: KMBookmark?
|
|
|
- var minimalCover = [KMBookmark]()
|
|
|
-
|
|
|
- for bm in items {
|
|
|
- if !(bm.isDescendant(of: lastBm)) {
|
|
|
- minimalCover.append(bm)
|
|
|
- lastBm = bm
|
|
|
- }
|
|
|
- }
|
|
|
- return minimalCover
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
|
|
- let bookmark = item as? KMBookmark ?? bookmarkRoot
|
|
|
- return bookmark.bookmarkType == .folder ? bookmark.children.count : 0
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
|
|
- let bookmark = item as! KMBookmark
|
|
|
- return bookmark.bookmarkType == .folder
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
|
|
- let bookmark = (item as? KMBookmark) ?? bookmarkRoot
|
|
|
- return bookmark.objectOfChidren(index: index)
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
|
|
|
- guard let column = tableColumn else { return nil }
|
|
|
- guard let bm = item as? KMBookmark else { return nil }
|
|
|
- let tcID = column.identifier
|
|
|
-
|
|
|
- switch tcID {
|
|
|
- case kLabelIdentifier:
|
|
|
- return [kTextWithIconStringKey: bm.label, kTextWithIconImageKey: bm.icon]
|
|
|
- case kFileIdentifier:
|
|
|
- if bm.bookmarkType == .folder || bm.bookmarkType == .session {
|
|
|
- let count = bm.children.count
|
|
|
- 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 kPageIdentifier:
|
|
|
- return bm.pageNumber
|
|
|
- default:
|
|
|
- return nil
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, byItem item: Any?) {
|
|
|
- guard let column = tableColumn else { return }
|
|
|
- guard let bm = item as? KMBookmark else { return }
|
|
|
- let tcID = column.identifier
|
|
|
-
|
|
|
- switch tcID {
|
|
|
- case kLabelIdentifier:
|
|
|
- if let newLabel = (object as? [String: Any])?[kTextWithIconStringKey] as? String, newLabel != bm.label {
|
|
|
- bm.label = newLabel
|
|
|
- }
|
|
|
- case kPageIdentifier:
|
|
|
- if let newPageNumber = object as? Int, newPageNumber != bm.pageNumber.intValue {
|
|
|
- bm.pageNumber = newPageNumber as NSNumber
|
|
|
- }
|
|
|
- default:
|
|
|
- break
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, writeItems items: [Any], to pboard: NSPasteboard) -> Bool {
|
|
|
- draggedBookmarks = minimumCoverForBookmarks(items as! [KMBookmark])
|
|
|
- pboard.clearContents()
|
|
|
- pboard.setData(Data(), forType: kPasteboardTypeBookmarkRows)
|
|
|
- return true
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
|
|
|
- guard index != NSOutlineViewDropOnItemIndex else { return [] }
|
|
|
-
|
|
|
- let pboard = info.draggingPasteboard
|
|
|
-
|
|
|
- if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
|
|
|
- return .move
|
|
|
- } else if NSURL.canReadFileURL(from: pboard) {
|
|
|
- return .every
|
|
|
- }
|
|
|
- return []
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
|
|
|
- let pboard = info.draggingPasteboard
|
|
|
-
|
|
|
- if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
|
|
|
- var movedBookmarks = [KMBookmark]()
|
|
|
- var indexes = IndexSet()
|
|
|
- var insertionIndex = index
|
|
|
-
|
|
|
- let targetItem = item as? KMBookmark ?? 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(index: bookmarkIndex)
|
|
|
- targetItem.insert(child: bookmark, atIndex: 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 {
|
|
|
- let urls = NSURL.readFileURLs(from: pboard)
|
|
|
-
|
|
|
- let newBookmarks = KMBookmark.bookmarks(urls: urls)
|
|
|
- if !newBookmarks.isEmpty {
|
|
|
- var indexes = IndexSet(integersIn: index..<(index + newBookmarks.count))
|
|
|
- (item as? KMBookmark ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
|
|
|
- if (item as? KMBookmark ?? bookmarkRoot) === bookmarkRoot || ov.isItemExpanded(item) {
|
|
|
- if (item as? KMBookmark ?? bookmarkRoot) !== 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.removeAll()
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
- // MARK: NSOutlineViewDelegate
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> Any? {
|
|
|
- if tableColumn == nil {
|
|
|
- return (item as? KMBookmark)?.bookmarkType == .separator ? KMSeparatorCell() : 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 }
|
|
|
- guard let cell = cell as? NSCell else { return }
|
|
|
-
|
|
|
- if column.identifier == kFileIdentifier {
|
|
|
- if let bm = item as? KMBookmark {
|
|
|
-// if bm.bookmarkType == .folder || bm.bookmarkType == .session {
|
|
|
-// cell.textColor = .disabledControlTextColor
|
|
|
-// } else {
|
|
|
-// cell.textColor = .controlTextColor
|
|
|
-// }
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, shouldEdit tableColumn: NSTableColumn?, item: Any) -> Bool {
|
|
|
- guard let column = tableColumn else { return false }
|
|
|
- guard let bm = item as? KMBookmark else { return false }
|
|
|
-
|
|
|
- let tcID = column.identifier
|
|
|
- switch tcID {
|
|
|
- case kLabelIdentifier:
|
|
|
- return bm.bookmarkType != .separator
|
|
|
- case kPageIdentifier:
|
|
|
- return bm.pageIndex != NSNotFound
|
|
|
- default:
|
|
|
- return false
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, toolTipFor cell: NSCell, rect: UnsafeMutablePointer<NSRect>, tableColumn tc: NSTableColumn?, item: Any, mouseLocation: NSPoint) -> String {
|
|
|
- guard let column = tc else { return "" }
|
|
|
- guard let bm = item as? KMBookmark else { return "" }
|
|
|
-
|
|
|
- let tcID = column.identifier
|
|
|
- switch tcID {
|
|
|
- case kLabelIdentifier:
|
|
|
- return bm.label
|
|
|
- case kFileIdentifier:
|
|
|
- if bm.bookmarkType == .session {
|
|
|
- return ""
|
|
|
-// return bm.children.map { $0.path ?? "" }.joined(separator: "\n")
|
|
|
- } else if bm.bookmarkType == .folder {
|
|
|
- let count = bm.children.count
|
|
|
- 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 kPageIdentifier:
|
|
|
- return bm.pageNumber.stringValue
|
|
|
- default:
|
|
|
- return ""
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineViewSelectionDidChange(_ notification: Notification) {
|
|
|
- updateStatus()
|
|
|
- if QLPreviewPanel.sharedPreviewPanelExists(), let previewPanel = QLPreviewPanel.shared(), previewPanel.isVisible, previewPanel.dataSource === self {
|
|
|
- previewPanel.reloadData()
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, deleteItems items: [Any]) {
|
|
|
- for item in minimumCoverForBookmarks(items as! [KMBookmark]).reversed() {
|
|
|
- guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue }
|
|
|
- parent.removeObjectFromChildren(index: 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! [KMBookmark]), &urls)
|
|
|
- if !urls.isEmpty {
|
|
|
- let pboard = NSPasteboard.general
|
|
|
- pboard.clearContents()
|
|
|
- pboard.writeObjects(urls as [NSPasteboardWriting])
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, canCopyItems items: [Any]) -> Bool {
|
|
|
- return !items.isEmpty
|
|
|
- }
|
|
|
-
|
|
|
- func outlineView(_ ov: NSOutlineView, pasteFromPasteboard pboard: NSPasteboard) {
|
|
|
- let urls = NSURL.readFileURLs(from: pboard)
|
|
|
-
|
|
|
- let newBookmarks = KMBookmark.bookmarks(urls: urls)
|
|
|
- if !newBookmarks.isEmpty {
|
|
|
- var item: KMBookmark?
|
|
|
- var anIndex = 0
|
|
|
- getInsertionFolder(&item, childIndex: &anIndex)
|
|
|
- var 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)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- 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..<count {
|
|
|
- if let label = ov.item(atRow: i) {
|
|
|
- labels.append(label as! String)
|
|
|
- }
|
|
|
- }
|
|
|
- return labels
|
|
|
- }
|
|
|
-
|
|
|
-// func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String) {
|
|
|
-// statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("No match: \"%@\"", comment: "Status message"), searchString))
|
|
|
+//extension KMBookmarkController: NSOutlineViewDelegate, NSOutlineViewDataSource {
|
|
|
+// //MARK: NSOutlineViewDataSource
|
|
|
+//
|
|
|
+// func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] {
|
|
|
+// var lastBm: KMBookmark?
|
|
|
+// var minimalCover = [KMBookmark]()
|
|
|
+//
|
|
|
+// for bm in items {
|
|
|
+// if !(bm.isDescendant(of: lastBm)) {
|
|
|
+// minimalCover.append(bm)
|
|
|
+// lastBm = bm
|
|
|
+// }
|
|
|
+// }
|
|
|
+// return minimalCover
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
|
|
|
+// let bookmark = item as? KMBookmark ?? bookmarkRoot
|
|
|
+// return bookmark.bookmarkType == .folder ? bookmark.children.count : 0
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, isItemExpandable item: Any) -> Bool {
|
|
|
+// let bookmark = item as! KMBookmark
|
|
|
+// return bookmark.bookmarkType == .folder
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
|
|
|
+// let bookmark = (item as? KMBookmark) ?? bookmarkRoot
|
|
|
+// return bookmark.objectOfChidren(index: index)
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
|
|
|
+// guard let column = tableColumn else { return nil }
|
|
|
+// guard let bm = item as? KMBookmark else { return nil }
|
|
|
+// let tcID = column.identifier
|
|
|
+//
|
|
|
+// switch tcID {
|
|
|
+// case kLabelIdentifier:
|
|
|
+// return [kTextWithIconStringKey: bm.label, kTextWithIconImageKey: bm.icon]
|
|
|
+// case kFileIdentifier:
|
|
|
+// if bm.bookmarkType == .folder || bm.bookmarkType == .session {
|
|
|
+// let count = bm.children.count
|
|
|
+// 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 kPageIdentifier:
|
|
|
+// return bm.pageNumber
|
|
|
+// default:
|
|
|
+// return nil
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, byItem item: Any?) {
|
|
|
+// guard let column = tableColumn else { return }
|
|
|
+// guard let bm = item as? KMBookmark else { return }
|
|
|
+// let tcID = column.identifier
|
|
|
+//
|
|
|
+// switch tcID {
|
|
|
+// case kLabelIdentifier:
|
|
|
+// if let newLabel = (object as? [String: Any])?[kTextWithIconStringKey] as? String, newLabel != bm.label {
|
|
|
+// bm.label = newLabel
|
|
|
+// }
|
|
|
+// case kPageIdentifier:
|
|
|
+// if let newPageNumber = object as? Int, newPageNumber != bm.pageNumber.intValue {
|
|
|
+// bm.pageNumber = newPageNumber as NSNumber
|
|
|
+// }
|
|
|
+// default:
|
|
|
+// break
|
|
|
+// }
|
|
|
// }
|
|
|
//
|
|
|
-// func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String?) {
|
|
|
-// if let searchString = searchString {
|
|
|
-// statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("Finding: \"%@\"", comment: "Status message"), searchString))
|
|
|
+// func outlineView(_ ov: NSOutlineView, writeItems items: [Any], to pboard: NSPasteboard) -> Bool {
|
|
|
+// draggedBookmarks = minimumCoverForBookmarks(items as! [KMBookmark])
|
|
|
+// pboard.clearContents()
|
|
|
+// pboard.setData(Data(), forType: kPasteboardTypeBookmarkRows)
|
|
|
+// return true
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
|
|
|
+// guard index != NSOutlineViewDropOnItemIndex else { return [] }
|
|
|
+//
|
|
|
+// let pboard = info.draggingPasteboard
|
|
|
+//
|
|
|
+// if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
|
|
|
+// return .move
|
|
|
+// } else if NSURL.canReadFileURL(from: pboard) {
|
|
|
+// return .every
|
|
|
+// }
|
|
|
+// return []
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
|
|
|
+// let pboard = info.draggingPasteboard
|
|
|
+//
|
|
|
+// if pboard.canReadItem(withDataConformingToTypes: [kPasteboardTypeBookmarkRows.rawValue]) && info.draggingSource as? NSOutlineView == ov {
|
|
|
+// var movedBookmarks = [KMBookmark]()
|
|
|
+// var indexes = IndexSet()
|
|
|
+// var insertionIndex = index
|
|
|
+//
|
|
|
+// let targetItem = item as? KMBookmark ?? 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(index: bookmarkIndex)
|
|
|
+// targetItem.insert(child: bookmark, atIndex: 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 {
|
|
|
-// updateStatus()
|
|
|
+// let urls = NSURL.readFileURLs(from: pboard)
|
|
|
+//
|
|
|
+// let newBookmarks = KMBookmark.bookmarks(urls: urls)
|
|
|
+// if !newBookmarks.isEmpty {
|
|
|
+// var indexes = IndexSet(integersIn: index..<(index + newBookmarks.count))
|
|
|
+// (item as? KMBookmark ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
|
|
|
+// if (item as? KMBookmark ?? bookmarkRoot) === bookmarkRoot || ov.isItemExpanded(item) {
|
|
|
+// if (item as? KMBookmark ?? bookmarkRoot) !== bookmarkRoot {
|
|
|
+// indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
|
|
|
+// }
|
|
|
+// ov.selectRowIndexes(indexes, byExtendingSelection: false)
|
|
|
+// }
|
|
|
+// return true
|
|
|
+// }
|
|
|
+// return false
|
|
|
// }
|
|
|
// }
|
|
|
-
|
|
|
- func addBookmarkURLsToArray(_ items: [KMBookmark], _ array: inout [URL]) {
|
|
|
- for bm in items {
|
|
|
- if bm.bookmarkType == .bookmark {
|
|
|
- if let url = bm.fileURL {
|
|
|
- array.append(url)
|
|
|
- }
|
|
|
- } else if bm.bookmarkType != .separator {
|
|
|
- addBookmarkURLsToArray(bm.children, &array)
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
-}
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, dragEndedWith operation: NSDragOperation) {
|
|
|
+// draggedBookmarks.removeAll()
|
|
|
+// }
|
|
|
+//
|
|
|
+//
|
|
|
+// // MARK: NSOutlineViewDelegate
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> Any? {
|
|
|
+// if tableColumn == nil {
|
|
|
+// return (item as? KMBookmark)?.bookmarkType == .separator ? KMSeparatorCell() : 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 }
|
|
|
+// guard let cell = cell as? NSCell else { return }
|
|
|
+//
|
|
|
+// if column.identifier == kFileIdentifier {
|
|
|
+// if let bm = item as? KMBookmark {
|
|
|
+//// if bm.bookmarkType == .folder || bm.bookmarkType == .session {
|
|
|
+//// cell.textColor = .disabledControlTextColor
|
|
|
+//// } else {
|
|
|
+//// cell.textColor = .controlTextColor
|
|
|
+//// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, shouldEdit tableColumn: NSTableColumn?, item: Any) -> Bool {
|
|
|
+// guard let column = tableColumn else { return false }
|
|
|
+// guard let bm = item as? KMBookmark else { return false }
|
|
|
+//
|
|
|
+// let tcID = column.identifier
|
|
|
+// switch tcID {
|
|
|
+// case kLabelIdentifier:
|
|
|
+// return bm.bookmarkType != .separator
|
|
|
+// case kPageIdentifier:
|
|
|
+// return bm.pageIndex != NSNotFound
|
|
|
+// default:
|
|
|
+// return false
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, toolTipFor cell: NSCell, rect: UnsafeMutablePointer<NSRect>, tableColumn tc: NSTableColumn?, item: Any, mouseLocation: NSPoint) -> String {
|
|
|
+// guard let column = tc else { return "" }
|
|
|
+// guard let bm = item as? KMBookmark else { return "" }
|
|
|
+//
|
|
|
+// let tcID = column.identifier
|
|
|
+// switch tcID {
|
|
|
+// case kLabelIdentifier:
|
|
|
+// return bm.label
|
|
|
+// case kFileIdentifier:
|
|
|
+// if bm.bookmarkType == .session {
|
|
|
+// return ""
|
|
|
+//// return bm.children.map { $0.path ?? "" }.joined(separator: "\n")
|
|
|
+// } else if bm.bookmarkType == .folder {
|
|
|
+// let count = bm.children.count
|
|
|
+// 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 kPageIdentifier:
|
|
|
+// return bm.pageNumber.stringValue
|
|
|
+// default:
|
|
|
+// return ""
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineViewSelectionDidChange(_ notification: Notification) {
|
|
|
+// updateStatus()
|
|
|
+// if QLPreviewPanel.sharedPreviewPanelExists(), let previewPanel = QLPreviewPanel.shared(), previewPanel.isVisible, previewPanel.dataSource === self {
|
|
|
+// previewPanel.reloadData()
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, deleteItems items: [Any]) {
|
|
|
+// for item in minimumCoverForBookmarks(items as! [KMBookmark]).reversed() {
|
|
|
+// guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue }
|
|
|
+// parent.removeObjectFromChildren(index: 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! [KMBookmark]), &urls)
|
|
|
+// if !urls.isEmpty {
|
|
|
+// let pboard = NSPasteboard.general
|
|
|
+// pboard.clearContents()
|
|
|
+// pboard.writeObjects(urls as [NSPasteboardWriting])
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, canCopyItems items: [Any]) -> Bool {
|
|
|
+// return !items.isEmpty
|
|
|
+// }
|
|
|
+//
|
|
|
+// func outlineView(_ ov: NSOutlineView, pasteFromPasteboard pboard: NSPasteboard) {
|
|
|
+// let urls = NSURL.readFileURLs(from: pboard)
|
|
|
+//
|
|
|
+// let newBookmarks = KMBookmark.bookmarks(urls: urls)
|
|
|
+// if !newBookmarks.isEmpty {
|
|
|
+// var item: KMBookmark?
|
|
|
+// var anIndex = 0
|
|
|
+// getInsertionFolder(&item, childIndex: &anIndex)
|
|
|
+// var 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)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// 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..<count {
|
|
|
+// if let label = ov.item(atRow: i) {
|
|
|
+// labels.append(label as! String)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// return labels
|
|
|
+// }
|
|
|
+//
|
|
|
+//// func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String) {
|
|
|
+//// statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("No match: \"%@\"", comment: "Status message"), searchString))
|
|
|
+//// }
|
|
|
+////
|
|
|
+//// func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String?) {
|
|
|
+//// if let searchString = searchString {
|
|
|
+//// statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("Finding: \"%@\"", comment: "Status message"), searchString))
|
|
|
+//// } else {
|
|
|
+//// updateStatus()
|
|
|
+//// }
|
|
|
+//// }
|
|
|
+//
|
|
|
+// func addBookmarkURLsToArray(_ items: [KMBookmark], _ array: inout [URL]) {
|
|
|
+// for bm in items {
|
|
|
+// if bm.bookmarkType == .bookmark {
|
|
|
+// if let url = bm.fileURL {
|
|
|
+// array.append(url)
|
|
|
+// }
|
|
|
+// } else if bm.bookmarkType != .separator {
|
|
|
+// addBookmarkURLsToArray(bm.children, &array)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+//}
|
|
|
|
|
|
extension KMBookmarkController: NSToolbarDelegate, NSToolbarItemValidation {
|
|
|
func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
|
|
@@ -869,6 +786,81 @@ extension KMBookmarkController: NSMenuDelegate, NSMenuItemValidation {
|
|
|
// }
|
|
|
return true
|
|
|
}
|
|
|
+
|
|
|
+ // MARK: - NSMenu delegate methods
|
|
|
+ func addItemForBookmark(_ bookmark: KMBookmark, toMenu menu: NSMenu, isFolder: Bool, isAlternate: Bool) {
|
|
|
+ var item: NSMenuItem?
|
|
|
+ if isFolder {
|
|
|
+ item = menu.addItemWithSubmenuAndTitle(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 = NSEvent.ModifierFlags.option
|
|
|
+ item?.isAlternate = true
|
|
|
+ item?.setImageAndSize(bookmark.alternateIcon)
|
|
|
+ } else {
|
|
|
+ item?.setImageAndSize(bookmark.icon)
|
|
|
+ }
|
|
|
+ }
|
|
|
+//
|
|
|
+ func menuNeedsUpdate(_ menu: NSMenu) {
|
|
|
+ if menu == bookmarkOutlineView.outlineView.menu {
|
|
|
+ let row = bookmarkOutlineView.outlineView.clickedRow
|
|
|
+ menu.removeAllItems()
|
|
|
+ if row != -1 {
|
|
|
+ menu.addItem(withTitle: NSLocalizedString("Remove", comment: "Menu item title"), action: #selector(deleteMenuBookmarks), 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 {
|
|
|
+ let supermenu = menu.supermenu
|
|
|
+ if supermenu != nil {
|
|
|
+ let idx = supermenu!.indexOfItem(withSubmenu: menu)
|
|
|
+ let bm = (supermenu == NSApp.mainMenu) ? bookmarkRoot : supermenu!.item(at: idx)?.representedObject as? KMBookmark
|
|
|
+
|
|
|
+ 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 {
|
|
|
+ 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)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
extension NSURL {
|
|
@@ -891,3 +883,28 @@ extension NSURL {
|
|
|
return []
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+extension KMBookmarkController {
|
|
|
+ func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] {
|
|
|
+ var lastBm: KMBookmark?
|
|
|
+ var minimalCover = [KMBookmark]()
|
|
|
+
|
|
|
+ for bm in items {
|
|
|
+ if !(bm.isDescendant(of: lastBm)) {
|
|
|
+ minimalCover.append(bm)
|
|
|
+ lastBm = bm
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return minimalCover
|
|
|
+ }
|
|
|
+
|
|
|
+ func clickedBookmarks() -> [Any]? {
|
|
|
+ let row = bookmarkOutlineView.outlineView.clickedRow
|
|
|
+ guard row != -1 else { return nil }
|
|
|
+ var indexes = bookmarkOutlineView.outlineView.selectedRowIndexes
|
|
|
+ if !indexes.contains(row) {
|
|
|
+ indexes = IndexSet(integer: row)
|
|
|
+ }
|
|
|
+ return indexes.compactMap { bookmarkOutlineView.outlineView.item(atRow: $0) }
|
|
|
+ }
|
|
|
+}
|