KMPreferenceController.swift 20 KB

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