|
@@ -49,12 +49,8 @@ class KMBookmarkController: NSWindowController {
|
|
|
override func windowDidLoad() {
|
|
|
super.windowDidLoad()
|
|
|
setupToolbar()
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ 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 {
|
|
|
|
|
|
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+ @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 menuHasKeyEquivalent(_ menu: NSMenu, for event: NSEvent, target: AutoreleasingUnsafeMutablePointer<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
func setupToolbar() {
|
|
|
|
|
|
let toolbar = NSToolbar(identifier: kBookmarksToolbarIdentifier)
|
|
@@ -508,315 +425,315 @@ class KMBookmarkController: NSWindowController {
|
|
|
|
|
|
}
|
|
|
|
|
|
-extension KMBookmarkController: NSOutlineViewDelegate, 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()
|
|
|
- }
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- 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 {
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- 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 ""
|
|
|
-
|
|
|
- } 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 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
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ 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())
|
|
|
+
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ 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) }
|
|
|
+ }
|
|
|
+}
|