KMBookmarkController.swift 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. //
  2. // KMBookmarkController.swift
  3. // PDF Reader Pro
  4. //
  5. // Created by lizhe on 2024/2/5.
  6. //
  7. import Cocoa
  8. let kBookmarksToolbarIdentifier = "BookmarksToolbarIdentifier"
  9. let kBookmarksNewFolderToolbarItemIdentifier = "BookmarksNewFolderToolbarItemIdentifier"
  10. let kBookmarksNewSeparatorToolbarItemIdentifier = "BookmarksNewSeparatorToolbarItemIdentifier"
  11. let kBookmarksDeleteToolbarItemIdentifier = "BookmarksDeleteToolbarItemIdentifier"
  12. class KMBookmarkController: NSWindowController {
  13. @IBOutlet weak var outlineView: NSOutlineView!
  14. var toolbarItems: [String: NSToolbarItem] = [:]
  15. override func windowDidLoad() {
  16. super.windowDidLoad()
  17. setupToolbar()
  18. // if let window = self.window, window.responds(to: #selector(setter: NSWindow.tabbingMode)) {
  19. // window.tabbingMode = .disallowed
  20. // }
  21. // windowFrameAutosaveName = SKBookmarksWindowFrameAutosaveName
  22. // window?.autorecalculatesContentBorderThickness = false
  23. // if UserDefaults.standard.bool(forKey: SKShowBookmarkStatusBarKey) == false {
  24. // toggleStatusBar(nil)
  25. // } else {
  26. // window?.setContentBorderThickness(22.0, for: .minY)
  27. // }
  28. // outlineView.setTypeSelectHelper(SKTypeSelectHelper.typeSelectHelper())
  29. // outlineView.registerForDraggedTypes([SKPasteboardTypeBookmarkRows, kUTTypeFileURL as String, NSFilenamesPboardType])
  30. // outlineView.doubleAction = #selector(doubleClickBookmark(_:))
  31. // outlineView.supportsQuickLook = true
  32. }
  33. // func updateStatus() {
  34. // let row = outlineView.selectedRow
  35. // var message = ""
  36. // if row != -1 {
  37. // if let bookmark = outlineView.item(atRow: row) as? KMBookmark {
  38. // switch bookmark.bookmarkType {
  39. // case .bookmark:
  40. // message = bookmark.fileURL?.path ?? ""
  41. // case .folder:
  42. // let count = bookmark.children.count
  43. // message = count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String(format: NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
  44. // default:
  45. // break
  46. // }
  47. // }
  48. // }
  49. //// statusBar.leftStringValue = message
  50. // }
  51. //
  52. static func showBookmarkController() -> KMBookmarkController {
  53. let controller = KMBookmarkController.init(windowNibName: "KMBookmarkController")
  54. NSWindow.currentWindow().addChildWindow(controller.window!, ordered: NSWindow.OrderingMode.above)
  55. controller.window?.center()
  56. return controller
  57. }
  58. //
  59. //
  60. // //MARK: Recent Documents
  61. // func recentDocumentInfo(at fileURL: URL) -> [String: Any]? {
  62. // let path = fileURL.path
  63. // for info in recentDocuments as! [[String: Any]] {
  64. // if let aliasData = info[ALIASDATA_KEY] as? Data,
  65. // let alias = SKAlias(aliasData),
  66. // alias.fileURLNoUI?.path.caseInsensitiveCompare(path) == .orderedSame {
  67. // return info
  68. // }
  69. // }
  70. // return nil
  71. // }
  72. //
  73. // func addRecentDocument(for fileURL: URL, pageIndex: UInt, scaleFactor factor: CGFloat, snapshots setups: [Any]?) {
  74. // guard let fileURL = fileURL else { return }
  75. //
  76. // if let info = recentDocumentInfo(at: fileURL) {
  77. // recentDocuments.removeObject(identicalTo: info)
  78. // }
  79. //
  80. // if let alias = SKAlias(url: fileURL) {
  81. // var bm: [String: Any] = [
  82. // PAGEINDEX_KEY: pageIndex,
  83. // SCALE_KEY: factor,
  84. // ALIASDATA_KEY: alias.data,
  85. // ALIAS_KEY: alias,
  86. // SNAPSHOTS_KEY: setups ?? []
  87. // ]
  88. // recentDocuments.insert(bm, at: 0)
  89. // if recentDocuments.count > maxRecentDocumentsCount {
  90. // recentDocuments.removeLastObject()
  91. // }
  92. // }
  93. // }
  94. //
  95. // func pageIndex(forRecentDocumentAt fileURL: URL) -> UInt {
  96. // guard let fileURL = fileURL else { return UInt.max }
  97. // if let pageIndex = recentDocumentInfo(at: fileURL)?[PAGEINDEX_KEY] as? UInt {
  98. // return pageIndex
  99. // }
  100. // return UInt.max
  101. // }
  102. //
  103. // func scaleFactor(forRecentDocumentAt fileURL: URL) -> CGFloat {
  104. // guard let fileURL = fileURL else { return 0 }
  105. // if let scaleFactor = recentDocumentInfo(at: fileURL)?[SCALE_KEY] as? CGFloat {
  106. // return scaleFactor
  107. // }
  108. // return 0
  109. // }
  110. //
  111. // func snapshots(forRecentDocumentAt fileURL: URL) -> [Any]? {
  112. // guard let fileURL = fileURL else { return nil }
  113. // if let setups = recentDocumentInfo(at: fileURL)?[SNAPSHOTS_KEY] as? [Any], !setups.isEmpty {
  114. // return setups
  115. // }
  116. // return nil
  117. // }
  118. //
  119. // //MARK: Bookmarks support
  120. // func getInsertionFolder(_ bookmarkPtr: inout SKBookmark?, childIndex indexPtr: inout UInt) {
  121. // let rowIndex = outlineView.clickedRow
  122. // var indexes = outlineView.selectedRowIndexes
  123. // if rowIndex != -1 && !indexes.contains(rowIndex) {
  124. // indexes = IndexSet(integer: rowIndex)
  125. // }
  126. // let rowIdx = indexes.last ?? NSNotFound
  127. //
  128. // var item = bookmarkRoot
  129. // var idx = bookmarkRoot.countOfChildren
  130. //
  131. // if rowIdx != NSNotFound {
  132. // if let selectedItem = outlineView.item(atRow: rowIdx) as? SKBookmark {
  133. // if outlineView.isItemExpanded(selectedItem) {
  134. // item = selectedItem
  135. // idx = item.countOfChildren
  136. // } else if let parent = selectedItem.parent, let itemIdx = parent.children.index(of: selectedItem) {
  137. // item = parent
  138. // idx = itemIdx + 1
  139. // }
  140. // }
  141. // }
  142. //
  143. // bookmarkPtr = item
  144. // indexPtr = idx
  145. // }
  146. //
  147. // @IBAction func openBookmark(_ sender: Any) {
  148. // if let bookmark = (sender as AnyObject).representedObject as? SKBookmark {
  149. // bookmark.open()
  150. // }
  151. // }
  152. //
  153. // @IBAction func doubleClickBookmark(_ sender: Any) {
  154. // let row = outlineView.clickedRow
  155. // if let bm = (row != -1 ? outlineView.item(atRow: row) : nil) as? SKBookmark,
  156. // [SKBookmarkType.bookmark, .session].contains(bm.bookmarkType) {
  157. // bm.open()
  158. // }
  159. // }
  160. //
  161. // @IBAction func insertBookmarkFolder(_ sender: Any) {
  162. // let folder = SKBookmark.bookmarkFolder(withLabel: NSLocalizedString("Folder", comment: "default folder name"))
  163. // var item: SKBookmark?
  164. // var idx: UInt = 0
  165. //
  166. // getInsertionFolder(&item, childIndex: &idx)
  167. // item?.insertObject(folder, inChildrenAtIndex: idx)
  168. //
  169. // if let row = outlineView.row(forItem: folder) {
  170. // outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
  171. // outlineView.editColumn(0, row: row, with: nil, select: true)
  172. // }
  173. // }
  174. //
  175. // @IBAction func insertBookmarkSeparator(_ sender: Any) {
  176. // let separator = SKBookmark.bookmarkSeparator()
  177. // var item: SKBookmark?
  178. // var idx: UInt = 0
  179. //
  180. // getInsertionFolder(&item, childIndex: &idx)
  181. // item?.insertObject(separator, inChildrenAtIndex: idx)
  182. //
  183. // if let row = outlineView.row(forItem: separator) {
  184. // outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
  185. // }
  186. // }
  187. //
  188. // @IBAction func addBookmark(_ sender: Any) {
  189. // let openPanel = NSOpenPanel()
  190. // var types = [String]()
  191. // for docClass in NSDocumentController.shared.documentClassNames {
  192. // if let docClass = NSClassFromString(docClass) as? NSDocument.Type {
  193. // types += docClass.readableTypes
  194. // }
  195. // }
  196. // openPanel.allowsMultipleSelection = true
  197. // openPanel.canChooseDirectories = true
  198. // openPanel.allowedFileTypes = types
  199. // openPanel.beginSheetModal(for: self.window!) { (result) in
  200. // guard result == .OK else { return }
  201. // let newBookmarks = SKBookmark.bookmarks(forURLs: openPanel.urls)
  202. // if !newBookmarks.isEmpty {
  203. // var item: SKBookmark?
  204. // var index: UInt = 0
  205. // self.getInsertionFolder(&item, childIndex: &index)
  206. // var indexes = IndexSet(integersIn: Int(index)..<Int(index + UInt(newBookmarks.count)))
  207. // item?.mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
  208. // if item == self.bookmarkRoot || self.outlineView.isItemExpanded(item) {
  209. // if item != self.bookmarkRoot {
  210. // indexes.shift(startingAt: 0, by: self.outlineView.row(forItem: item)! + 1)
  211. // }
  212. // self.outlineView.selectRowIndexes(indexes, byExtendingSelection: false)
  213. // }
  214. // }
  215. // }
  216. // }
  217. //
  218. // @IBAction func deleteBookmark(_ sender: Any) {
  219. // outlineView.delete(sender)
  220. // }
  221. //
  222. // @IBAction func toggleStatusBar(_ sender: Any) {
  223. // UserDefaults.standard.set(!statusBar.isVisible, forKey: SKShowBookmarkStatusBarKey)
  224. // statusBar.toggle(below: outlineView.enclosingScrollView, animate: sender != nil)
  225. // }
  226. //
  227. // func clickedBookmarks() -> [Any]? {
  228. // let row = outlineView.clickedRow
  229. // guard row != -1 else { return nil }
  230. // var indexes = outlineView.selectedRowIndexes
  231. // if !indexes.contains(row) {
  232. // indexes = IndexSet(integer: row)
  233. // }
  234. // return indexes.compactMap { outlineView.item(atRow: $0) }
  235. // }
  236. //
  237. // @IBAction func deleteBookmarks(_ sender: Any) {
  238. // guard let items = clickedBookmarks() as? [SKBookmark] else { return }
  239. // endEditing()
  240. // for item in items.reversed() {
  241. // if let parent = item.parent, let itemIndex = parent.children.index(of: item) {
  242. // parent.removeObject(fromChildrenAtIndex: itemIndex)
  243. // }
  244. // }
  245. // }
  246. //
  247. // @IBAction func openBookmarks(_ sender: Any) {
  248. // guard let items = clickedBookmarks() as? [SKBookmark] else { return }
  249. // for item in items.reversed() {
  250. // item.open()
  251. // }
  252. // }
  253. //
  254. // @IBAction func previewBookmarks(_ sender: Any) {
  255. // if QLPreviewPanel.sharedPreviewPanelExists() && QLPreviewPanel.shared().isVisible {
  256. // QLPreviewPanel.shared().orderOut(nil)
  257. // } else if let row = outlineView.clickedRow {
  258. // outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false)
  259. // QLPreviewPanel.shared().makeKeyAndOrderFront(nil)
  260. // }
  261. // }
  262. //
  263. //
  264. // // MARK: - NSMenu delegate methods
  265. //
  266. // func addItemForBookmark(_ bookmark: SKBookmark, toMenu menu: NSMenu, isFolder: Bool, isAlternate: Bool) {
  267. // var item: NSMenuItem?
  268. // if isFolder {
  269. // item = menu.addItem(withSubmenuAndTitle: bookmark.label)
  270. // item?.submenu?.delegate = self
  271. // } else {
  272. // item = menu.addItem(withTitle: bookmark.label, action: #selector(openBookmark(_:)), target: self)
  273. // }
  274. // item?.representedObject = bookmark
  275. // if isAlternate {
  276. // item?.keyEquivalentModifierMask = .alternate
  277. // item?.isAlternate = true
  278. // item?.setImageAndSize(bookmark.alternateIcon)
  279. // } else {
  280. // item?.setImageAndSize(bookmark.icon)
  281. // }
  282. // }
  283. //
  284. // func menuNeedsUpdate(_ menu: NSMenu) {
  285. // if menu == outlineView.menu {
  286. // let row = outlineView.clickedRow
  287. // menu.removeAllItems()
  288. // if row != -1 {
  289. // menu.addItem(withTitle: NSLocalizedString("Remove", comment: "Menu item title"), action: #selector(deleteBookmarks(_:)), target: self)
  290. // menu.addItem(withTitle: NSLocalizedString("Open", comment: "Menu item title"), action: #selector(openBookmarks(_:)), target: self)
  291. // menu.addItem(withTitle: NSLocalizedString("Quick Look", comment: "Menu item title"), action: #selector(previewBookmarks(_:)), target: self)
  292. // menu.addItem(.separator())
  293. // }
  294. // menu.addItem(withTitle: NSLocalizedString("New Folder", comment: "Menu item title"), action: #selector(insertBookmarkFolder(_:)), target: self)
  295. // menu.addItem(withTitle: NSLocalizedString("New Separator", comment: "Menu item title"), action: #selector(insertBookmarkSeparator(_:)), target: self)
  296. // } else {
  297. // 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 }
  298. //
  299. // let bookmarks = bm.children
  300. // var i = menu.numberOfItems
  301. //
  302. // while i > 0 {
  303. // if let menuItem = menu.item(at: i - 1), menuItem.isSeparatorItem || menuItem.representedObject != nil {
  304. // menu.removeItem(menuItem)
  305. // }
  306. // i -= 1
  307. // }
  308. //
  309. // if supermenu == NSApp.mainMenu, let previousSession = previousSession {
  310. // menu.addItem(.separator())
  311. // addItemForBookmark(previousSession, toMenu: menu, isFolder: false, isAlternate: false)
  312. // addItemForBookmark(previousSession, toMenu: menu, isFolder: true, isAlternate: true)
  313. // }
  314. //
  315. // if menu.numberOfItems > 0, bookmarks.count > 0 {
  316. // menu.addItem(.separator())
  317. // }
  318. //
  319. // for bm in bookmarks {
  320. // switch bm.bookmarkType {
  321. // case .folder:
  322. // addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: false)
  323. // addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: true)
  324. // case .session:
  325. // addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false)
  326. // addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: true)
  327. // case .separator:
  328. // menu.addItem(.separator())
  329. // default:
  330. // addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false)
  331. // }
  332. // }
  333. // }
  334. // }
  335. //
  336. // // avoid rebuilding the bookmarks menu on every key event
  337. // func menuHasKeyEquivalent(_ menu: NSMenu, for event: NSEvent, target: AutoreleasingUnsafeMutablePointer<AnyObject?>?, action: UnsafeMutablePointer<Selector?>?) -> Bool { false }
  338. //
  339. //
  340. // // MARK: - NSOutlineView datasource methods
  341. // func minimumCoverForBookmarks(_ items: [SKBookmark]) -> [SKBookmark] {
  342. // var lastBm: SKBookmark?
  343. // var minimalCover = [SKBookmark]()
  344. //
  345. // for bm in items {
  346. // if !(bm.isDescendant(of: lastBm)) {
  347. // minimalCover.append(bm)
  348. // lastBm = bm
  349. // }
  350. // }
  351. // return minimalCover
  352. // }
  353. //
  354. // func outlineView(_ ov: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
  355. // let bookmark = item as? SKBookmark ?? bookmarkRoot
  356. // return bookmark.bookmarkType == .folder ? bookmark.countOfChildren : 0
  357. // }
  358. //
  359. // func outlineView(_ ov: NSOutlineView, isItemExpandable item: Any) -> Bool {
  360. // let bookmark = item as! SKBookmark
  361. // return bookmark.bookmarkType == .folder
  362. // }
  363. //
  364. // func outlineView(_ ov: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
  365. // let bookmark = (item as? SKBookmark) ?? bookmarkRoot
  366. // return bookmark.objectInChildren(at: index)!
  367. // }
  368. //
  369. // func outlineView(_ ov: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? {
  370. // guard let column = tableColumn, let tcID = column.identifier else { return nil }
  371. // guard let bm = item as? SKBookmark else { return nil }
  372. //
  373. // switch tcID {
  374. // case LABEL_COLUMNID:
  375. // return [SKTextWithIconStringKey: bm.label, SKTextWithIconImageKey: bm.icon]
  376. // case FILE_COLUMNID:
  377. // if bm.bookmarkType == .folder || bm.bookmarkType == .session {
  378. // let count = bm.countOfChildren
  379. // return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
  380. // } else {
  381. // return bm.fileURL?.path ?? ""
  382. // }
  383. // case PAGE_COLUMNID:
  384. // return bm.pageNumber
  385. // default:
  386. // return nil
  387. // }
  388. // }
  389. //
  390. // func outlineView(_ ov: NSOutlineView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, byItem item: Any?) {
  391. // guard let column = tableColumn, let tcID = column.identifier else { return }
  392. // guard let bm = item as? SKBookmark else { return }
  393. //
  394. // switch tcID {
  395. // case LABEL_COLUMNID:
  396. // if let newLabel = (object as? [String: Any])?[SKTextWithIconStringKey] as? String, newLabel != bm.label {
  397. // bm.label = newLabel
  398. // }
  399. // case PAGE_COLUMNID:
  400. // if let newPageNumber = object as? Int, newPageNumber != bm.pageNumber {
  401. // bm.pageNumber = newPageNumber
  402. // }
  403. // default:
  404. // break
  405. // }
  406. // }
  407. //
  408. // func outlineView(_ ov: NSOutlineView, writeItems items: [Any], to pboard: NSPasteboard) -> Bool {
  409. // draggedBookmarks = minimumCoverForBookmarks(items as! [SKBookmark])
  410. // pboard.clearContents()
  411. // pboard.setData(Data(), forType: SKPasteboardTypeBookmarkRows)
  412. // return true
  413. // }
  414. //
  415. // func outlineView(_ ov: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation {
  416. // guard index != NSOutlineViewDropOnItemIndex else { return .none }
  417. // guard let pboard = info.draggingPasteboard else { return .none }
  418. //
  419. // if pboard.canReadItem(withDataConformingToTypes: [SKPasteboardTypeBookmarkRows]) && info.draggingSource as? NSOutlineView == ov {
  420. // return .move
  421. // } else if NSURL.canReadFileURL(from: pboard) {
  422. // return .every
  423. // }
  424. // return .none
  425. // }
  426. //
  427. // func outlineView(_ ov: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool {
  428. // guard let pboard = info.draggingPasteboard else { return false }
  429. //
  430. // if pboard.canReadItem(withDataConformingToTypes: [SKPasteboardTypeBookmarkRows]) && info.draggingSource as? NSOutlineView == ov {
  431. // var movedBookmarks = [SKBookmark]()
  432. // var indexes = IndexSet()
  433. // var insertionIndex = index
  434. //
  435. // let targetItem = item as? SKBookmark ?? bookmarkRoot
  436. //
  437. // endEditing()
  438. // for bookmark in draggedBookmarks {
  439. // guard let parent = bookmark.parent else { continue }
  440. // guard let bookmarkIndex = parent.children.firstIndex(of: bookmark) else { continue }
  441. //
  442. // if targetItem == parent {
  443. // if insertionIndex > bookmarkIndex {
  444. // insertionIndex -= 1
  445. // }
  446. // if insertionIndex == bookmarkIndex {
  447. // continue
  448. // }
  449. // }
  450. // parent.removeObjectFromChildren(at: bookmarkIndex)
  451. // targetItem.insertObject(bookmark, inChildrenAtIndex: insertionIndex)
  452. // movedBookmarks.append(bookmark)
  453. // insertionIndex += 1
  454. // }
  455. //
  456. // for bookmark in movedBookmarks {
  457. // let row = ov.row(forItem: bookmark)
  458. // if row != -1 {
  459. // indexes.insert(row)
  460. // }
  461. // }
  462. // if !indexes.isEmpty {
  463. // ov.selectRowIndexes(indexes, byExtendingSelection: false)
  464. // }
  465. // return true
  466. // } else {
  467. // guard let urls = NSURL.readFileURLs(from: pboard) else { return false }
  468. //
  469. // let newBookmarks = SKBookmark.bookmarks(for: urls)
  470. // if !newBookmarks.isEmpty {
  471. // endEditing()
  472. // let indexes = IndexSet(integersIn: index..<(index + newBookmarks.count))
  473. // (item as? SKBookmark ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
  474. // if item === bookmarkRoot || ov.isItemExpanded(item) {
  475. // if item !== bookmarkRoot {
  476. // indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
  477. // }
  478. // ov.selectRowIndexes(indexes, byExtendingSelection: false)
  479. // }
  480. // return true
  481. // }
  482. // return false
  483. // }
  484. // }
  485. //
  486. // func outlineView(_ ov: NSOutlineView, dragEndedWith operation: NSDragOperation) {
  487. // draggedBookmarks = nil
  488. // }
  489. //
  490. // // MARK: - NSOutlineView delegate methods
  491. //
  492. // func outlineView(_ ov: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> Any? {
  493. // if tableColumn == nil {
  494. // return (item as? SKBookmark)?.bookmarkType == .separator ? SKSeparatorCell() : nil
  495. // }
  496. // return tableColumn?.dataCell(forRow: ov.row(forItem: item))
  497. // }
  498. //
  499. // func outlineView(_ ov: NSOutlineView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, item: Any) {
  500. // guard let column = tableColumn else { return }
  501. //
  502. // if column.identifier == FILE_COLUMNID {
  503. // if let bm = item as? SKBookmark {
  504. // if bm.bookmarkType == .folder || bm.bookmarkType == .session {
  505. // (cell as? NSCell)?.textColor = .disabledControlTextColor
  506. // } else {
  507. // (cell as? NSCell)?.textColor = .controlTextColor
  508. // }
  509. // }
  510. // }
  511. // }
  512. //
  513. // func outlineView(_ ov: NSOutlineView, shouldEditTableColumn tableColumn: NSTableColumn?, item: Any) -> Bool {
  514. // guard let column = tableColumn, let tcID = column.identifier else { return false }
  515. // guard let bm = item as? SKBookmark else { return false }
  516. //
  517. // switch tcID {
  518. // case LABEL_COLUMNID:
  519. // return bm.bookmarkType != .separator
  520. // case PAGE_COLUMNID:
  521. // return bm.pageIndex != NSNotFound
  522. // default:
  523. // return false
  524. // }
  525. // }
  526. //
  527. // func outlineView(_ ov: NSOutlineView, toolTipFor cell: NSCell, rect: UnsafeMutablePointer<NSRect>, tableColumn tc: NSTableColumn?, item: Any, mouseLocation: NSPoint) -> String {
  528. // guard let column = tc, let tcID = column.identifier else { return "" }
  529. // guard let bm = item as? SKBookmark else { return "" }
  530. //
  531. // switch tcID {
  532. // case LABEL_COLUMNID:
  533. // return bm.label
  534. // case FILE_COLUMNID:
  535. // if bm.bookmarkType == .session {
  536. // return bm.children.map { $0.path ?? "" }.joined(separator: "\n")
  537. // } else if bm.bookmarkType == .folder {
  538. // let count = bm.countOfChildren
  539. // return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count)
  540. // } else {
  541. // return bm.fileURL?.path ?? ""
  542. // }
  543. // case PAGE_COLUMNID:
  544. // return bm.pageNumber?.stringValue ?? ""
  545. // default:
  546. // return ""
  547. // }
  548. // }
  549. //
  550. // func outlineViewSelectionDidChange(_ notification: Notification) {
  551. // updateStatus()
  552. // if QLPreviewPanel.sharedPreviewPanelExists(), let previewPanel = QLPreviewPanel.shared() as? QLPreviewPanel, previewPanel.isVisible, previewPanel.dataSource === self {
  553. // previewPanel.reloadData()
  554. // }
  555. // }
  556. //
  557. // func outlineView(_ ov: NSOutlineView, deleteItems items: [Any]) {
  558. // endEditing()
  559. // for item in minimumCoverForBookmarks(items as! [SKBookmark]).reversed() {
  560. // guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue }
  561. // parent.removeObjectFromChildren(at: itemIndex)
  562. // }
  563. // }
  564. //
  565. // func outlineView(_ ov: NSOutlineView, canDeleteItems items: [Any]) -> Bool {
  566. // return !items.isEmpty
  567. // }
  568. //
  569. // func outlineView(_ ov: NSOutlineView, copyItems items: [Any]) {
  570. // var urls = [URL]()
  571. // addBookmarkURLsToArray(minimumCoverForBookmarks(items as! [SKBookmark]), urls)
  572. // if !urls.isEmpty {
  573. // let pboard = NSPasteboard.general
  574. // pboard.clearContents()
  575. // pboard.writeObjects(urls as [NSPasteboardWriting])
  576. // } else {
  577. // NSBeep()
  578. // }
  579. // }
  580. //
  581. // func outlineView(_ ov: NSOutlineView, canCopyItems items: [Any]) -> Bool {
  582. // return !items.isEmpty
  583. // }
  584. //
  585. // func outlineView(_ ov: NSOutlineView, pasteFromPasteboard pboard: NSPasteboard) {
  586. // guard let urls = NSURL.readFileURLs(from: pboard), !urls.isEmpty else { NSBeep(); return }
  587. //
  588. // let newBookmarks = SKBookmark.bookmarks(for: urls)
  589. // if !newBookmarks.isEmpty {
  590. // var item: SKBookmark?
  591. // var anIndex = 0
  592. // getInsertionFolder(&item, childIndex: &anIndex)
  593. // let indexes = IndexSet(integersIn: anIndex..<(anIndex + newBookmarks.count))
  594. // (item ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes)
  595. // if item === bookmarkRoot || ov.isItemExpanded(item) {
  596. // if item !== bookmarkRoot {
  597. // indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1)
  598. // }
  599. // ov.selectRowIndexes(indexes, byExtendingSelection: false)
  600. // }
  601. // } else {
  602. // NSBeep()
  603. // }
  604. // }
  605. //
  606. // func outlineView(_ ov: NSOutlineView, canPasteFromPasteboard pboard: NSPasteboard) -> Bool {
  607. // return NSURL.canReadFileURL(from: pboard)
  608. // }
  609. //
  610. // func outlineView(_ ov: NSOutlineView, typeSelectHelperSelectionStrings typeSelectHelper: SKTypeSelectHelper) -> [String] {
  611. // let count = ov.numberOfRows
  612. // var labels = [String]()
  613. // for i in 0..<count {
  614. // if let label = ov.item(atRow: i) as? SKBookmark?.label {
  615. // labels.append(label)
  616. // }
  617. // }
  618. // return labels
  619. // }
  620. //
  621. // func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, didFailToFindMatchForSearchString searchString: String) {
  622. // statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("No match: \"%@\"", comment: "Status message"), searchString))
  623. // }
  624. //
  625. // func outlineView(_ ov: NSOutlineView, typeSelectHelper typeSelectHelper: SKTypeSelectHelper, updateSearchString searchString: String?) {
  626. // if let searchString = searchString {
  627. // statusBar.setLeftStringValue(String.localizedStringWithFormat(NSLocalizedString("Finding: \"%@\"", comment: "Status message"), searchString))
  628. // } else {
  629. // updateStatus()
  630. // }
  631. // }
  632. //
  633. // // MARK: - Toolbar
  634. //
  635. func setupToolbar() {
  636. // Create a new toolbar instance, and attach it to our document window
  637. let toolbar = NSToolbar(identifier: kBookmarksToolbarIdentifier)
  638. var dict = [String: NSToolbarItem]()
  639. // Set up toolbar properties: Allow customization, give a default display mode, and remember state in user defaults
  640. toolbar.allowsUserCustomization = true
  641. toolbar.autosavesConfiguration = true
  642. toolbar.displayMode = .default
  643. // We are the delegate
  644. toolbar.delegate = self
  645. // Add template toolbar items
  646. var item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(kBookmarksNewFolderToolbarItemIdentifier))
  647. item.label = NSLocalizedString("New Folder", comment: "Toolbar item label")
  648. // item.setLabels(NSLocalizedString("New Folder", comment: "Toolbar item label"))
  649. item.toolTip = NSLocalizedString("Add a New Folder", comment: "Tool tip message")
  650. item.image = NSImage(named: "NewFolder")
  651. item.target = self
  652. // item.action = #selector(insertBookmarkFolder(_:))
  653. dict[kBookmarksNewFolderToolbarItemIdentifier] = item
  654. item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(kBookmarksNewSeparatorToolbarItemIdentifier))
  655. item.label = NSLocalizedString("New Separator", comment: "Toolbar item label")
  656. // item.setLabels(NSLocalizedString("New Separator", comment: "Toolbar item label"))
  657. item.toolTip = NSLocalizedString("Add a New Separator", comment: "Tool tip message")
  658. item.image = NSImage(named: "NewSeparator")
  659. item.target = self
  660. // item.action = #selector(insertBookmarkSeparator(_:))
  661. dict[kBookmarksNewSeparatorToolbarItemIdentifier] = item
  662. item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(kBookmarksDeleteToolbarItemIdentifier))
  663. item.label = NSLocalizedString("Delete", comment: "Toolbar item label")
  664. // item.setLabels(NSLocalizedString("Delete", comment: "Toolbar item label"))
  665. item.toolTip = NSLocalizedString("Delete Selected Items", comment: "Tool tip message")
  666. item.image = NSWorkspace.shared.icon(forFileType: NSFileTypeForHFSTypeCode(OSType(kToolbarDeleteIcon)))
  667. item.target = self
  668. // item.action = #selector(deleteBookmark(_:))
  669. dict[kBookmarksDeleteToolbarItemIdentifier] = item
  670. toolbarItems = dict
  671. // Attach the toolbar to the window
  672. self.window?.toolbar = toolbar
  673. }
  674. // func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdent: String, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
  675. // return toolbarItems[itemIdent]
  676. // }
  677. // func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [String] {
  678. // return [
  679. // kBookmarksNewFolderToolbarItemIdentifier,
  680. // kBookmarksNewSeparatorToolbarItemIdentifier,
  681. // kBookmarksDeleteToolbarItemIdentifier
  682. // ]
  683. // }
  684. //
  685. // func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [String] {
  686. // return [
  687. // kBookmarksNewFolderToolbarItemIdentifier,
  688. // kBookmarksNewSeparatorToolbarItemIdentifier,
  689. // kBookmarksDeleteToolbarItemIdentifier
  690. //// NSToolbarItem.Identifier.customizeToolbar
  691. //// NSToolbarFlexibleSpaceItemIdentifier,
  692. //// NSToolbarSpaceItemIdentifier,
  693. //// NSToolbarSeparatorItemIdentifier,
  694. //// NSToolbarCustomizeToolbarItemIdentifier
  695. // ]
  696. // }
  697. func validateToolbarItem(_ toolbarItem: NSToolbarItem) -> Bool {
  698. // guard let toolbar = self.window?.toolbar else { return false }
  699. //
  700. // if toolbar.customizationPaletteIsRunning {
  701. // return false
  702. // } else if toolbarItem.itemIdentifier == kBookmarksDeleteToolbarItemIdentifier {
  703. // return outlineView.canDelete
  704. // }
  705. return true
  706. }
  707. func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
  708. // if menuItem.action == #selector(toggleStatusBar(_:)) {
  709. // if statusBar.isVisible {
  710. // menuItem.title = NSLocalizedString("Hide Status Bar", comment: "Menu item title")
  711. // } else {
  712. // menuItem.title = NSLocalizedString("Show Status Bar", comment: "Menu item title")
  713. // }
  714. // return true
  715. // } else if menuItem.action == #selector(addBookmark(_:)) {
  716. // return menuItem.tag == 0
  717. // }
  718. return true
  719. }
  720. //
  721. // // MARK: - Quick Look Panel Support
  722. //
  723. // func acceptsPreviewPanelControl(_ panel: QLPreviewPanel) -> Bool {
  724. // return true
  725. // }
  726. //
  727. // func beginPreviewPanelControl(_ panel: QLPreviewPanel) {
  728. // panel.delegate = self
  729. // panel.dataSource = self
  730. // }
  731. //
  732. // func endPreviewPanelControl(_ panel: QLPreviewPanel) {
  733. // }
  734. //
  735. // func previewItems() -> [SKBookmark] {
  736. // var items = [SKBookmark]()
  737. //
  738. // outlineView.selectedRowIndexes.enumerated().forEach { (idx, _) in
  739. // if let item = outlineView.item(atRow: idx) as? SKBookmark {
  740. // if item.bookmarkType == .bookmark {
  741. // items.append(item)
  742. // } else if item.bookmarkType == .session {
  743. // items.append(contentsOf: item.children)
  744. // }
  745. // }
  746. // }
  747. // return items
  748. // }
  749. //
  750. // func numberOfPreviewItems(in panel: QLPreviewPanel) -> Int {
  751. // return previewItems().count
  752. // }
  753. //
  754. // func previewPanel(_ panel: QLPreviewPanel, previewItemAt anIndex: Int) -> QLPreviewItem {
  755. // return previewItems()[anIndex]
  756. // }
  757. //
  758. // func previewPanel(_ panel: QLPreviewPanel, sourceFrameOnScreenForPreviewItem item: QLPreviewItem) -> NSRect {
  759. // var item = item
  760. // if let parent = (item as? SKBookmark)?.parent, parent.bookmarkType == .session {
  761. // item = parent
  762. // }
  763. // let row = outlineView.row(forItem: item)
  764. // var iconRect = NSZeroRect
  765. // if let item = item as? SKBookmark, row != -1 {
  766. // let cell = outlineView.preparedCell(atColumn: 0, row: row) as? SKTextWithIconCell
  767. // iconRect = cell?.iconRect(forBounds: outlineView.frameOfCell(atColumn: 0, row: row)) ?? NSZeroRect
  768. // if outlineView.visibleRect.intersects(iconRect) {
  769. // iconRect = outlineView.convert(iconRect, to: nil)
  770. // } else {
  771. // iconRect = NSZeroRect
  772. // }
  773. // }
  774. // return iconRect
  775. // }
  776. //
  777. // func previewPanel(_ panel: QLPreviewPanel, transitionImageForPreviewItem item: QLPreviewItem, contentRect: UnsafeMutablePointer<NSRect>) -> NSImage? {
  778. // var item = item
  779. // if let parent = (item as? SKBookmark)?.parent, parent.bookmarkType == .session {
  780. // item = parent
  781. // }
  782. // return (item as? SKBookmark)?.icon
  783. // }
  784. //
  785. // func previewPanel(_ panel: QLPreviewPanel, handle event: NSEvent) -> Bool {
  786. // if event.type == .keyDown {
  787. // outlineView.keyDown(with: event)
  788. // return true
  789. // }
  790. // return false
  791. // }
  792. //
  793. }
  794. extension KMBookmarkController: NSToolbarDelegate {
  795. func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
  796. // return [.flexibleSpace, .yourItem1, .yourItem2, .yourItem3]
  797. return [
  798. NSToolbarItem.Identifier(kBookmarksNewFolderToolbarItemIdentifier),
  799. NSToolbarItem.Identifier(kBookmarksNewSeparatorToolbarItemIdentifier),
  800. NSToolbarItem.Identifier(kBookmarksDeleteToolbarItemIdentifier)
  801. ]
  802. }
  803. func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
  804. // return [.yourItem1, .yourItem2, .yourItem3, .flexibleSpace, .space]
  805. return [
  806. NSToolbarItem.Identifier(kBookmarksNewFolderToolbarItemIdentifier),
  807. NSToolbarItem.Identifier(kBookmarksNewSeparatorToolbarItemIdentifier),
  808. NSToolbarItem.Identifier(kBookmarksDeleteToolbarItemIdentifier),
  809. .flexibleSpace,
  810. .space
  811. ]
  812. }
  813. func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
  814. return toolbarItems[itemIdentifier.rawValue]
  815. // let toolbarItem = NSToolbarItem(itemIdentifier: itemIdentifier)
  816. // toolbarItem.label = "Your Item Label"
  817. // toolbarItem.paletteLabel = "Your Item Palette Label"
  818. // toolbarItem.target = self
  819. // toolbarItem.action = #selector(yourAction(_:))
  820. // toolbarItem.image = NSImage(named: "YourItemImageName")
  821. // return toolbarItem
  822. }
  823. }