KMPreferenceController.swift 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492
  1. //
  2. // KMPreferenceController.swift
  3. // PDF Master
  4. //
  5. // Created by tangchao on 2023/11/7.
  6. //
  7. import Cocoa
  8. class KMPreferenceWindow: NSWindow {
  9. // override func responds(to aSelector: Selector!) -> Bool {
  10. // return aSelector != #selector(toggleToolbarShow) && aSelector != #selector(runToolbarCustomizationPalette) && super.responds(to: aSelector)
  11. // }
  12. }
  13. private let SKPreferencesToolbarIdentifier = "SKPreferencesToolbarIdentifier"
  14. private let SKPreferenceWindowFrameAutosaveName = "SKPreferenceWindow"
  15. private let BOTTOM_MARGIN = 27.0
  16. private let SKLastSelectedPreferencePaneKey = "SKLastSelectedPreferencePane"
  17. private let NIBNAME_KEY = "nibName"
  18. @objc protocol KMPreferencePane: NSObjectProtocol {
  19. @objc optional func defaultsDidRevert()
  20. }
  21. class KMPreferenceController: NSWindowController {
  22. var preferencePanes: [KMPreferencePane]?
  23. var history: [NSViewController]?
  24. var historyIndex: Int = 0
  25. var currentPane: KMPreferencePane?
  26. private let INITIALUSERDEFAULTS_KEY = "InitialUserDefaults"
  27. private let RESETTABLEKEYS_KEY = "ResettableKeys"
  28. /*
  29. @class SKIBArray;
  30. @protocol ;
  31. @interface SKPreferenceController : NSWindowController <NSWindowDelegate, NSTabViewDelegate, NSToolbarDelegate> {
  32. NSArray *resetButtons;
  33. }
  34. @property (nonatomic, retain) IBOutlet NSArray *resetButtons;
  35. + (id)sharedPrefenceController;
  36. - (IBAction)resetAll:(id)sender;
  37. - (IBAction)resetCurrent:(id)sender;
  38. - (IBAction)doGoToNextPage:(id)sender;
  39. - (IBAction)doGoToPreviousPage:(id)sender;
  40. - (IBAction)doGoToFirstPage:(id)sender;
  41. - (IBAction)doGoToLastPage:(id)sender;
  42. - (IBAction)doGoBack:(id)sender;
  43. - (IBAction)doGoForward:(id)sender;
  44. - (IBAction)changeFont:(id)sender;
  45. - (IBAction)changeAttributes:(id)sender;
  46. - (void)selectPaneWithIdentifier:(NSString *)itemIdentifier;
  47. @end
  48. @interface SKIBArray : NSArray {
  49. __strong id object[9];
  50. unsigned long mutations;
  51. }
  52. //@property (nonatomic, retain) id object;
  53. @property (nonatomic, retain) IBOutlet id object1, object2, object3, object4, object5, object6, object7, object8, object9;
  54. @end
  55. */
  56. deinit {
  57. KMPrint("KMPreferenceController deinit.")
  58. // currentPane = nil;
  59. }
  60. static let shared = KMPreferenceController(windowNibName: "PreferenceWindow")
  61. override func windowDidLoad() {
  62. super.windowDidLoad()
  63. self.preferencePanes = [KMGeneralPreferences(), KMDisplayPreferences(), KMNotesPreferences(), KMSyncPreferences()]
  64. self.history = []
  65. self.historyIndex = 0
  66. if #available(macOS 11.0,*) {
  67. self.window?.toolbarStyle = .expanded
  68. }
  69. let window = self.window
  70. let toolbar = NSToolbar(identifier: SKPreferencesToolbarIdentifier)
  71. toolbar.allowsUserCustomization = false
  72. toolbar.autosavesConfiguration = false
  73. toolbar.isVisible = true
  74. toolbar.delegate = self
  75. window?.toolbar = toolbar
  76. window?.showsToolbarButton = false
  77. window?.contentView?.wantsLayer = true
  78. // we want to restore the top of the window, while without the force it restores the bottom position without the size
  79. window?.setFrameUsingName(SKPreferenceWindowFrameAutosaveName, force: true)
  80. self.windowFrameAutosaveName = SKPreferenceWindowFrameAutosaveName
  81. // [NSGraphicsContext SKAutoSizeButtons:resetButtons rightAlign:false];
  82. var width = 0.0
  83. var frame: NSRect = .zero
  84. var pane: NSViewController?
  85. var view: NSView?
  86. for pane in self.preferencePanes ?? [] {
  87. let _pane = pane as! NSViewController
  88. width = fmax(width, NSWidth(_pane.view.frame))
  89. }
  90. for pane in self.preferencePanes ?? [] {
  91. let _pane = pane as! NSViewController
  92. view = _pane.view
  93. frame = view!.frame
  94. if let data = view?.autoresizingMask.contains(.width), data {
  95. frame.size.width = width
  96. } else {
  97. frame.origin.x = floor(0.5 * (width - NSWidth(frame)))
  98. }
  99. frame.origin.y = BOTTOM_MARGIN
  100. view?.frame = frame
  101. }
  102. self.currentPane = self._preferencePane(forItemIdentifier: UserDefaults.standard.string(forKey: SKLastSelectedPreferencePaneKey) ?? "") ?? self.preferencePanes![0]
  103. toolbar.selectedItemIdentifier = NSToolbarItem.Identifier((self.currentPane as? NSViewController)?.nibName ?? "")
  104. if let _currentPane = self.currentPane as? NSViewController {
  105. window?.title = _currentPane.title ?? ""
  106. self.history?.append(_currentPane)
  107. }
  108. view = (self.currentPane as? NSViewController)?.view
  109. frame = window?.frame ?? .zero
  110. frame.size.width = width
  111. frame = KMShrinkRect(rect: frame, amount: NSHeight(window?.contentView?.frame ?? .zero) - NSMaxY(view!.frame), edge: .minY)
  112. window?.setFrame(frame, display: false)
  113. if let data = view {
  114. window?.contentView?.addSubview(data)
  115. }
  116. }
  117. @IBAction func changeFont(_ sender: AnyObject?) {
  118. self.window?.contentView?.activeFontWell()?.changeFontFromFontManager(sender)
  119. }
  120. /*
  121. - (void)selectPaneWithIdentifier:(NSString *)itemIdentifier {
  122. [self selectPane:[self preferencePaneForItemIdentifier:itemIdentifier]];
  123. }
  124. #pragma mark Actions
  125. - (IBAction)doGoToNextPage:(id)sender {
  126. NSUInteger itemIndex = [preferencePanes indexOfObject:currentPane];
  127. if (itemIndex != NSNotFound && ++itemIndex < [preferencePanes count])
  128. [self selectPane:[preferencePanes objectAtIndex:itemIndex]];
  129. }
  130. - (IBAction)doGoToPreviousPage:(id)sender {
  131. NSUInteger itemIndex = [preferencePanes indexOfObject:currentPane];
  132. if (itemIndex != NSNotFound && itemIndex-- > 0)
  133. [self selectPane:[preferencePanes objectAtIndex:itemIndex]];
  134. }
  135. - (IBAction)doGoToFirstPage:(id)sender {
  136. [self selectPane:[preferencePanes objectAtIndex:0]];
  137. }
  138. - (IBAction)doGoToLastPage:(id)sender {
  139. [self selectPane:[preferencePanes lastObject]];
  140. }
  141. - (IBAction)doGoBack:(id)sender {
  142. if (historyIndex > 0) {
  143. historyIndex--;
  144. [self selectPane:nil];
  145. }
  146. }
  147. - (IBAction)doGoForward:(id)sender {
  148. if (historyIndex + 1 < [history count]) {
  149. historyIndex++;
  150. [self selectPane:nil];
  151. }
  152. }
  153. - (IBAction)changeAttributes:(id)sender {
  154. // [[[[self window] contentView] activeFontWell] changeAttributesFromFontManager:sender];
  155. }
  156. - (BOOL)validateMenuItem:(NSMenuItem *)menuItem {
  157. if ([menuItem action] == @selector(doGoToNextPage:) || [menuItem action] == @selector(doGoToLastPage:))
  158. return [currentPane isEqual:[preferencePanes lastObject]] == NO;
  159. else if ([menuItem action] == @selector(doGoToPreviousPage:) || [menuItem action] == @selector(doGoToFirstPage:))
  160. return [currentPane isEqual:[preferencePanes objectAtIndex:0]] == NO;
  161. else if ([menuItem action] == @selector(doGoBack:))
  162. return historyIndex > 0;
  163. else if ([menuItem action] == @selector(doGoForward:))
  164. return historyIndex + 1 < [history count];
  165. return YES;
  166. }
  167. #pragma mark Toolbar
  168. @end
  169. @implementation SKIBArray
  170. static void setObjectAtIndex(id __strong *object, id obj, NSUInteger i, unsigned long *mutationsPtr) {
  171. if (object[i] != obj) {
  172. // [object[i] release];
  173. object[i] = obj;
  174. (*mutationsPtr)++;
  175. }
  176. }
  177. #define SYNTHESIZE_OBJECT_ACCESSORS(i) \
  178. @dynamic object##i; \
  179. - (id)object##i { return object[i-1]; } \
  180. - (void)setObject##i:(id)obj { setObjectAtIndex(object, obj, i-1, &mutations); }
  181. SYNTHESIZE_OBJECT_ACCESSORS(1)
  182. SYNTHESIZE_OBJECT_ACCESSORS(2)
  183. SYNTHESIZE_OBJECT_ACCESSORS(3)
  184. SYNTHESIZE_OBJECT_ACCESSORS(4)
  185. SYNTHESIZE_OBJECT_ACCESSORS(5)
  186. SYNTHESIZE_OBJECT_ACCESSORS(6)
  187. SYNTHESIZE_OBJECT_ACCESSORS(7)
  188. SYNTHESIZE_OBJECT_ACCESSORS(8)
  189. SYNTHESIZE_OBJECT_ACCESSORS(9)
  190. - (void)dealloc {
  191. NSUInteger i;
  192. for (i = 0; i < 9; i++)
  193. setObjectAtIndex(object, nil, i, &mutations);
  194. // [super dealloc];
  195. }
  196. - (NSUInteger)count {
  197. NSUInteger i;
  198. for (i = 0; i < 9; i++)
  199. if (object[i] == nil) break;
  200. return i;
  201. }
  202. - (id)objectAtIndex:(NSUInteger)anIndex {
  203. return object[anIndex];
  204. }
  205. - (NSUInteger)countByEnumeratingWithState:(NSFastEnumerationState *)state objects:(id *)stackbuf count:(NSUInteger)len {
  206. if (state->state == 0) {
  207. state->state = 1;
  208. // state->itemsPtr = object;
  209. state->mutationsPtr = &mutations;
  210. return [self count];
  211. }
  212. return 0;
  213. }
  214. @end
  215. */
  216. @IBAction func resetCurrent(_ sender: AnyObject?) {
  217. if (self.currentPane == nil) {
  218. return
  219. }
  220. let label = (self.currentPane as? NSViewController)?.title ?? ""
  221. let alert = NSAlert()
  222. alert.messageText = String(format: KMLocalizedString("Reset %@ preferences to their original values?", "Message in alert dialog when pressing Reset All button"), label)
  223. alert.informativeText = String(format: KMLocalizedString("Choosing Reset will restore all settings in this pane to the state they were in when PDF Reader Pro Edition was first installed.", "Informative text in alert dialog when pressing Reset All button"), label)
  224. alert.addButton(withTitle: KMLocalizedString("Reset", "Button title"))
  225. alert.addButton(withTitle: KMLocalizedString("Cancel", "Button title"))
  226. alert.beginSheetModal(for: self.window!, modalDelegate: self, didEnd: #selector(_resetCurrentSheetDidEnd), contextInfo: nil)
  227. }
  228. @IBAction func resetAll(_ sender: AnyObject?) {
  229. let alert = NSAlert()
  230. alert.messageText = KMLocalizedString("Reset all preferences to their original values?", "Message in alert dialog when pressing Reset All button")
  231. alert.informativeText = KMLocalizedString("Choosing Reset will restore all settings to the state they were in when PDF Reader Pro Edition was first installed.", "Informative text in alert dialog when pressing Reset All button")
  232. alert.addButton(withTitle: KMLocalizedString("Reset", "Button title"))
  233. alert.addButton(withTitle: KMLocalizedString("Cancel", "Button title"))
  234. let response = alert.runModal()
  235. if (response == .alertFirstButtonReturn) {
  236. NSUserDefaultsController.shared.revertToInitialValues(forKeys: nil)
  237. for pane in self.preferencePanes! {
  238. pane.defaultsDidRevert?()
  239. }
  240. //重置OCR后,记录切换值
  241. // [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"KMStatusPlanPopUpBtnKey"];
  242. // [[NSUserDefaults standardUserDefaults] synchronize];
  243. }
  244. }
  245. }
  246. // MARK: - Private Methods
  247. extension KMPreferenceController {
  248. private func _preferencePane(forItemIdentifier itemIdent: String) -> KMPreferencePane? {
  249. self._panelControlSelectColor(itemIdent)
  250. for pane in self.preferencePanes ?? [] {
  251. let _pane = pane as! NSViewController
  252. if _pane.nibName == itemIdent {
  253. return pane
  254. }
  255. }
  256. return nil
  257. }
  258. private func _panelControlSelectColor(_ identifier: String) {
  259. for item in self.window?.toolbar?.items ?? [] {
  260. if item.itemIdentifier.rawValue == identifier {
  261. if item.itemIdentifier.rawValue == "GeneralPreferences" {
  262. item.image = NSImage(named: "KMImageNameElseSettingsGeneralSel")
  263. } else if item.itemIdentifier.rawValue == "DisplayPreferences" {
  264. item.image = NSImage(named: "KMImageNameElseSettingsViewSel")
  265. } else if item.itemIdentifier.rawValue == "NotesPreferences" {
  266. item.image = NSImage(named: "KMImageNameElseSettingsAnnotationSel")
  267. } else if item.itemIdentifier.rawValue == "SyncPreferences" {
  268. item.image = NSImage(named: "KMImageNameElseSettingsSynchronizeSel")
  269. } else if item.itemIdentifier.rawValue == "DropboxPreferences" {
  270. item.image = NSImage(named: "KMImageNameElseSettingsDropboxSel")
  271. }
  272. } else {
  273. if item.itemIdentifier.rawValue == "GeneralPreferences" {
  274. item.image = NSImage(named: "KMImageNameElseSettingsGeneralNor")
  275. } else if item.itemIdentifier.rawValue == "DisplayPreferences" {
  276. item.image = NSImage(named: "KMImageNameElseSettingsViewNor")
  277. } else if item.itemIdentifier.rawValue == "NotesPreferences" {
  278. item.image = NSImage(named: "KMImageNameElseSettingsAnnotationNor")
  279. } else if item.itemIdentifier.rawValue == "SyncPreferences" {
  280. item.image = NSImage(named: "KMImageNameElseSettingsSynchronizeNor")
  281. } else if item.itemIdentifier.rawValue == "DropboxPreferences" {
  282. item.image = NSImage(named: "KMImageNameElseSettingsDropboxNor")
  283. }
  284. }
  285. }
  286. }
  287. @objc private func _selectPaneAction(_ sender: AnyObject?) {
  288. let _item = sender as? NSToolbarItem
  289. self._panelControlSelectColor(_item?.itemIdentifier.rawValue ?? "")
  290. if let pane = self._preferencePane(forItemIdentifier: _item?.itemIdentifier.rawValue ?? "") {
  291. self._selectPane(pane)
  292. }
  293. }
  294. private func _selectPane(_ pane: KMPreferencePane) {
  295. var _pane = pane as? NSViewController
  296. let _currentPane = self.currentPane as? NSViewController
  297. if _pane != _currentPane {
  298. if (_pane != nil) {
  299. self.historyIndex += 1
  300. if self.history!.count > self.historyIndex {
  301. let range = self.historyIndex ..< self.history!.count-self.historyIndex
  302. self.history?.removeSubrange(range)
  303. }
  304. self.history?.append(_pane!)
  305. } else {
  306. _pane = self.history?[self.historyIndex]
  307. }
  308. let window = self.window
  309. let contentView = window!.contentView
  310. let oldView = _currentPane!.view
  311. let view = _pane!.view
  312. var frame = window!.frame
  313. frame = KMShrinkRect(rect: frame, amount: NSHeight(contentView!.frame) - NSMaxY(view.frame), edge: .minY)
  314. // make sure edits are committed
  315. _currentPane?.commitEditing()
  316. NSUserDefaultsController.shared.commitEditing()
  317. self.currentPane = pane
  318. window?.title = (self.currentPane as? NSViewController)?.title ?? ""
  319. if let data = (self.currentPane as? NSViewController)?.nibName {
  320. UserDefaults.standard.setValue(data, forKey: SKLastSelectedPreferencePaneKey)
  321. window?.toolbar?.selectedItemIdentifier = NSToolbarItem.Identifier(data)
  322. }
  323. if UserDefaults.standard.bool(forKey: SKDisableAnimationsKey) {
  324. contentView?.replaceSubview(oldView, with: view)
  325. window?.setFrame(frame, display: true)
  326. } else {
  327. let duration = window?.animationResizeTime(frame)
  328. contentView?.displayIfNeeded()
  329. NSAnimationContext.runAnimationGroup { context in
  330. context.duration = duration!
  331. contentView?.animator().replaceSubview(oldView, with: view)
  332. window?.animator().setFrame(frame, display: true)
  333. }
  334. }
  335. }
  336. }
  337. @objc private func _resetCurrentSheetDidEnd(_ alert: NSAlert, _ returnCode: Int, _ contextInfo: Any) {
  338. if (returnCode == NSApplication.ModalResponse.alertFirstButtonReturn.rawValue) {
  339. let initialUserDefaultsURL = Bundle.main.url(forResource: INITIALUSERDEFAULTS_KEY, withExtension: "plist")
  340. if let _currentPane = self.currentPane as? NSViewController {
  341. let resettableKeys = (NSDictionary(contentsOf: initialUserDefaultsURL!)?.object(forKey: RESETTABLEKEYS_KEY) as? NSDictionary)?.object(forKey: _currentPane.nibName!)
  342. if let data = resettableKeys as? [String] {
  343. NSUserDefaultsController.shared.revertToInitialValues(forKeys: data)
  344. }
  345. self.currentPane?.defaultsDidRevert?()
  346. // if ([[currentPane title] isEqualToString:@"OCR"]) { //重置OCR后,记录切换值
  347. // [[NSUserDefaults standardUserDefaults] setInteger:0 forKey:@"KMStatusPlanPopUpBtnKey"];
  348. // [[NSUserDefaults standardUserDefaults] synchronize];
  349. // }
  350. }
  351. }
  352. }
  353. }
  354. extension KMPreferenceController: NSToolbarDelegate {
  355. func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? {
  356. // NSViewController<SKPreferencePane> * = [self preferencePaneForItemIdentifier:itemIdent];
  357. let pane = self._preferencePane(forItemIdentifier: itemIdentifier.rawValue) as? NSViewController
  358. // NSToolbarItem * = [[NSToolbarItem alloc] initWithItemIdentifier:itemIdent];
  359. let item = NSToolbarItem(itemIdentifier: itemIdentifier)
  360. item.label = pane?.title ?? ""
  361. var ima: NSImage?
  362. if itemIdentifier.rawValue == "GeneralPreferences" {
  363. ima = NSImage(named: "KMImageNameElseSettingsGeneralNor")
  364. } else if itemIdentifier.rawValue == "DisplayPreferences" {
  365. ima = NSImage(named: "KMImageNameElseSettingsViewNor")
  366. } else if itemIdentifier.rawValue == "NotesPreferences" {
  367. ima = NSImage(named: "KMImageNameElseSettingsAnnotationNor")
  368. } else if itemIdentifier.rawValue == "SyncPreferences" {
  369. ima = NSImage(named: "KMImageNameElseSettingsSynchronizeNor")
  370. } else if itemIdentifier.rawValue == "DropboxPreferences" {
  371. ima = NSImage(named: "KMImageNameElseSettingsDropboxNor")
  372. }
  373. item.image = ima
  374. item.target = self
  375. item.action = #selector(_selectPaneAction)
  376. return item;
  377. }
  378. func toolbarDefaultItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
  379. var items: [NSToolbarItem.Identifier] = []
  380. for item in self.preferencePanes ?? [] {
  381. let name = (item as? NSViewController)?.nibName
  382. items.append(NSToolbarItem.Identifier(rawValue: name!))
  383. }
  384. return items
  385. }
  386. func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
  387. return self.toolbarDefaultItemIdentifiers(toolbar)
  388. }
  389. func toolbarSelectableItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] {
  390. return self.toolbarDefaultItemIdentifiers(toolbar)
  391. }
  392. }
  393. extension KMPreferenceController: NSWindowDelegate {
  394. func windowDidResignMain(_ notification: Notification) {
  395. self.window?.contentView?.deactivateWellSubcontrols()
  396. }
  397. func windowWillClose(_ notification: Notification) {
  398. (self.currentPane as? NSViewController)?.commitEditing()
  399. NSUserDefaultsController.shared.commitEditing()
  400. }
  401. }