|
@@ -7,12 +7,846 @@
|
|
|
|
|
|
import Cocoa
|
|
|
|
|
|
-class KMBookmarkController: NSWindowController {
|
|
|
+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 SKBookmark?, 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 = bookmarkRoot
|
|
|
+// var idx = bookmarkRoot.countOfChildren
|
|
|
+//
|
|
|
+// if rowIdx != NSNotFound {
|
|
|
+// if let selectedItem = outlineView.item(atRow: rowIdx) as? SKBookmark {
|
|
|
+// if outlineView.isItemExpanded(selectedItem) {
|
|
|
+// item = selectedItem
|
|
|
+// idx = item.countOfChildren
|
|
|
+// } else if let parent = selectedItem.parent, let itemIdx = parent.children.index(of: selectedItem) {
|
|
|
+// item = parent
|
|
|
+// idx = itemIdx + 1
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// bookmarkPtr = item
|
|
|
+// indexPtr = 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()
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// @IBAction func insertBookmarkFolder(_ sender: Any) {
|
|
|
+// let folder = SKBookmark.bookmarkFolder(withLabel: NSLocalizedString("Folder", comment: "default folder name"))
|
|
|
+// var item: SKBookmark?
|
|
|
+// var idx: UInt = 0
|
|
|
+//
|
|
|
+// getInsertionFolder(&item, childIndex: &idx)
|
|
|
+// item?.insertObject(folder, inChildrenAtIndex: idx)
|
|
|
+//
|
|
|
+// if 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 = SKBookmark.bookmarkSeparator()
|
|
|
+// var item: SKBookmark?
|
|
|
+// var idx: UInt = 0
|
|
|
+//
|
|
|
+// getInsertionFolder(&item, childIndex: &idx)
|
|
|
+// item?.insertObject(separator, inChildrenAtIndex: idx)
|
|
|
+//
|
|
|
+// if 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)..<Int(index + UInt(newBookmarks.count)))
|
|
|
+// item?.mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
|
|
|
+// if item == self.bookmarkRoot || self.outlineView.isItemExpanded(item) {
|
|
|
+// if item != self.bookmarkRoot {
|
|
|
+// indexes.shift(startingAt: 0, by: self.outlineView.row(forItem: item)! + 1)
|
|
|
+// }
|
|
|
+// self.outlineView.selectRowIndexes(indexes, byExtendingSelection: false)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// @IBAction func deleteBookmark(_ sender: Any) {
|
|
|
+// outlineView.delete(sender)
|
|
|
+// }
|
|
|
+//
|
|
|
+// @IBAction func toggleStatusBar(_ sender: Any) {
|
|
|
+// UserDefaults.standard.set(!statusBar.isVisible, forKey: SKShowBookmarkStatusBarKey)
|
|
|
+// 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? [SKBookmark] else { return }
|
|
|
+// endEditing()
|
|
|
+// 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<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool { false }
|
|
|
+//
|
|
|
+//
|
|
|
+// // MARK: - NSOutlineView datasource methods
|
|
|
+// func minimumCoverForBookmarks(_ items: [SKBookmark]) -> [SKBookmark] {
|
|
|
+// var lastBm: SKBookmark?
|
|
|
+// var minimalCover = [SKBookmark]()
|
|
|
+//
|
|
|
+// 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? 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
|
|
|
+//
|
|
|
+// endEditing()
|
|
|
+// 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 {
|
|
|
+// endEditing()
|
|
|
+// 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: - NSOutlineView delegate methods
|
|
|
+//
|
|
|
+// 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<NSRect>, 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]) {
|
|
|
+// endEditing()
|
|
|
+// 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..<count {
|
|
|
+// if let label = ov.item(atRow: i) as? SKBookmark?.label {
|
|
|
+// labels.append(label)
|
|
|
+// }
|
|
|
+// }
|
|
|
+// 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()
|
|
|
+// }
|
|
|
+// }
|
|
|
+//
|
|
|
+// // 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.setLabels(NSLocalizedString("New Folder", comment: "Toolbar item label"))
|
|
|
+ item.toolTip = NSLocalizedString("Add a New Folder", comment: "Tool tip message")
|
|
|
+ item.image = NSImage(named: "NewFolder")
|
|
|
+ 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.setLabels(NSLocalizedString("New Separator", comment: "Toolbar item label"))
|
|
|
+ item.toolTip = NSLocalizedString("Add a New Separator", comment: "Tool tip message")
|
|
|
+ item.image = NSImage(named: "NewSeparator")
|
|
|
+ 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.setLabels(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
|
|
|
+ }
|
|
|
+
|
|
|
+// func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdent: String, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
|
|
|
+// return toolbarItems[itemIdent]
|
|
|
+// }
|
|
|
+
|
|
|
+// func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [String] {
|
|
|
+// return [
|
|
|
+// kBookmarksNewFolderToolbarItemIdentifier,
|
|
|
+// kBookmarksNewSeparatorToolbarItemIdentifier,
|
|
|
+// kBookmarksDeleteToolbarItemIdentifier
|
|
|
+// ]
|
|
|
+// }
|
|
|
+//
|
|
|
+// func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [String] {
|
|
|
+// return [
|
|
|
+// kBookmarksNewFolderToolbarItemIdentifier,
|
|
|
+// kBookmarksNewSeparatorToolbarItemIdentifier,
|
|
|
+// kBookmarksDeleteToolbarItemIdentifier
|
|
|
+//// NSToolbarItem.Identifier.customizeToolbar
|
|
|
+//// NSToolbarFlexibleSpaceItemIdentifier,
|
|
|
+//// NSToolbarSpaceItemIdentifier,
|
|
|
+//// NSToolbarSeparatorItemIdentifier,
|
|
|
+//// NSToolbarCustomizeToolbarItemIdentifier
|
|
|
+// ]
|
|
|
+// }
|
|
|
+
|
|
|
+ func validateToolbarItem(_ toolbarItem: 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
|
|
|
+ }
|
|
|
|
|
|
- // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
|
|
|
+ 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
|
|
|
+ }
|
|
|
+//
|
|
|
+// // 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<NSRect>) -> 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: NSToolbarDelegate {
|
|
|
+ func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [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]
|
|
|
+// let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
|
|
|
+// toolbarItem.label = "Your Item Label"
|
|
|
+// toolbarItem.paletteLabel = "Your Item Palette Label"
|
|
|
+// toolbarItem.target = self
|
|
|
+// toolbarItem.action = #selector(yourAction(_:))
|
|
|
+// toolbarItem.image = NSImage(named: "YourItemImageName")
|
|
|
+// return toolbarItem
|
|
|
+ }
|
|
|
}
|