From df619ccc2c5db2004819873a39fa6b9ed6358292 Mon Sep 17 00:00:00 2001 From: igor Date: Thu, 9 Jan 2025 18:15:20 -0800 Subject: [PATCH] Cleaned up paths table. --- src/AppDelegate.swift | 14 ---- src/EditableNSTextField.swift | 10 +++ src/Helpers.swift | 17 +---- src/Makefile | 5 +- src/PathManager.swift | 15 +++-- ...ellView.swift => PathsTableCellView.swift} | 23 +++++-- src/PopoverPanel.swift | 6 -- src/ProgramsTableView.swift | 5 ++ src/SearchViewController.swift | 18 ++--- src/SettingsViewController.swift | 66 ++++++++----------- 10 files changed, 76 insertions(+), 103 deletions(-) rename src/{MyTableCellView.swift => PathsTableCellView.swift} (84%) create mode 100644 src/ProgramsTableView.swift diff --git a/src/AppDelegate.swift b/src/AppDelegate.swift index 56be162..4c72ef1 100644 --- a/src/AppDelegate.swift +++ b/src/AppDelegate.swift @@ -1,21 +1,13 @@ import Cocoa import Carbon import ServiceManagement -import OSLog class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { - fileprivate static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: AppDelegate.self) - ) - let fileManager = FileManager.default let window = PopoverPanel(viewController: SearchViewController()) func applicationDidFinishLaunching(_ notification: Notification) { - Self.logger.debug("applicationDidFinishLaunching") - PathManager.shared.rebuildIndex() window.delegate = self @@ -24,7 +16,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { HotKeyManager.shared.handler = { (inHandlerCallRef, inEvent, inUserData) -> OSStatus in - AppDelegate.logger.debug("Shortcut handler fired off.") if let delegate = NSApplication.shared.delegate as? AppDelegate { @@ -59,12 +50,9 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { //} func windowDidBecomeKey(_ notification: Notification) { - Self.logger.debug("Popover became key.") } func windowDidResignKey(_ notification: Notification) { - Self.logger.debug("Popover resigned key.") - if window.isVisible { window.orderOut(nil) } @@ -73,8 +61,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSWindowDelegate { func applicationShouldHandleReopen(_ sender: NSApplication, hasVisibleWindows: Bool) -> Bool { - Self.logger.debug("Application reopened.") - if !window.isKeyWindow { window.makeKeyAndOrderFront(nil) } diff --git a/src/EditableNSTextField.swift b/src/EditableNSTextField.swift index 07d14d6..ecc6333 100644 --- a/src/EditableNSTextField.swift +++ b/src/EditableNSTextField.swift @@ -1,10 +1,16 @@ import Cocoa +protocol EditableNSTextFieldDelegate: AnyObject { + func lostFocus() +} + final class EditableNSTextField: NSTextField { private let commandKey = NSEvent.ModifierFlags.command.rawValue private let commandShiftKey = NSEvent.ModifierFlags.command.rawValue | NSEvent.ModifierFlags.shift.rawValue + weak var auxiliaryDelegate: EditableNSTextFieldDelegate? + override func performKeyEquivalent(with event: NSEvent) -> Bool { if event.type == NSEvent.EventType.keyDown { if (event.modifierFlags.rawValue & @@ -50,4 +56,8 @@ final class EditableNSTextField: NSTextField { } return super.performKeyEquivalent(with: event) } + + override func textDidEndEditing(_ notification: Notification) { + auxiliaryDelegate?.lostFocus() + } } diff --git a/src/Helpers.swift b/src/Helpers.swift index 3bda404..f728d52 100644 --- a/src/Helpers.swift +++ b/src/Helpers.swift @@ -1,11 +1,5 @@ import AppKit import Carbon -import OSLog - -fileprivate let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String("Helpers") -) let OSCtrl = NSEvent.ModifierFlags.control.rawValue let OSCmd = NSEvent.ModifierFlags.command.rawValue @@ -29,13 +23,6 @@ enum ViewConstants { static let spacing40: CGFloat = 40 } -struct Program { - let path: String - let name: String - let ext: String - var img: NSImage? -} - func keyName(virtualKeyCode: UInt16) -> String? { let maxNameLength = 4 var nameBuffer = [UniChar](repeating: 0, count : maxNameLength) @@ -52,7 +39,7 @@ func keyName(virtualKeyCode: UInt16) -> String? { guard let ptr = TISGetInputSourceProperty(source, kTISPropertyUnicodeKeyLayoutData) else { - logger.log("Could not get keyboard layout data") + print("Could not get keyboard layout data") return nil } let layoutData = Unmanaged.fromOpaque(ptr) @@ -65,7 +52,7 @@ func keyName(virtualKeyCode: UInt16) -> String? { &deadKeys, maxNameLength, &nameLength, &nameBuffer) } guard osStatus == noErr else { - logger.debug("Code: \(virtualKeyCode) Status: \(osStatus)") + print("Code: \(virtualKeyCode) Status: \(osStatus)") return nil } diff --git a/src/Makefile b/src/Makefile index 8608f35..c43876e 100644 --- a/src/Makefile +++ b/src/Makefile @@ -10,8 +10,9 @@ EXEC = Grapp SRCMODULES = Helpers.swift EditableNSTextField.swift EventMonitor.swift \ GlobalEventTap.swift PopoverPanel.swift SearchViewController.swift \ SettingsViewController.swift HotKeyManager.swift \ - KeyDetectorButton.swift PathManager.swift MyTableCellView.swift \ - ProgramTableViewCell.swift AppDelegate.swift main.swift + KeyDetectorButton.swift PathManager.swift PathsTableCellView.swift \ + ProgramTableViewCell.swift ProgramsTableView.swift AppDelegate.swift \ + main.swift ARMOBJMODULES = $(addprefix ./arm64/,$(SRCMODULES:.swift=.o)) X86OBJMODULES = $(addprefix ./x86_64/,$(SRCMODULES:.swift=.o)) diff --git a/src/PathManager.swift b/src/PathManager.swift index b29d5eb..15ef278 100644 --- a/src/PathManager.swift +++ b/src/PathManager.swift @@ -1,12 +1,13 @@ import AppKit -import OSLog + +struct Program { + let path: String + let name: String + let ext: String + var img: NSImage? +} final class PathManager { - fileprivate static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: PathManager.self) - ) - static let shared = PathManager() // TODO: Filesystem events to watch changes on these directories and @@ -80,7 +81,7 @@ final class PathManager { } } } catch { - Self.logger.error("Error reading directory: \(error.localizedDescription, privacy: .public)") + print("Error reading directory: \(error.localizedDescription)") } } } diff --git a/src/MyTableCellView.swift b/src/PathsTableCellView.swift similarity index 84% rename from src/MyTableCellView.swift rename to src/PathsTableCellView.swift index 22010ba..046c9cc 100644 --- a/src/MyTableCellView.swift +++ b/src/PathsTableCellView.swift @@ -1,19 +1,21 @@ import AppKit -protocol MyTableCellViewDelegate: AnyObject { +protocol PathsTableCellViewDelegate: AnyObject { func selectionButtonClicked(tag: Int) func titleFieldTextChanged(tag: Int, text: String) func titleFieldFinishedEditing(tag: Int, text: String) } -class MyTableCellView: NSTableCellView, NSTextFieldDelegate { +class PathsTableCellView: NSTableCellView, NSTextFieldDelegate, + EditableNSTextFieldDelegate +{ var id: Int = -1 - weak var delegate: MyTableCellViewDelegate? + weak var delegate: PathsTableCellViewDelegate? private(set) var isEditing = false - public var titleField: NSTextField = { - let field = NSTextField() + public var titleField: EditableNSTextField = { + let field = EditableNSTextField() field.isEditable = false field.maximumNumberOfLines = 1 field.lineBreakMode = .byTruncatingTail @@ -38,6 +40,7 @@ class MyTableCellView: NSTableCellView, NSTextFieldDelegate { super.init(frame: frameRect) titleField.delegate = self + titleField.auxiliaryDelegate = self selectionButton.target = self selectionButton.action = #selector(makeSelection) @@ -74,15 +77,19 @@ class MyTableCellView: NSTableCellView, NSTextFieldDelegate { } public func startEditing() { + guard !isEditing else { return } isEditing = true titleField.isEditable = true window?.makeFirstResponder(titleField) } public func stopEditing() { + guard isEditing else { return } isEditing = false titleField.isEditable = false window?.makeFirstResponder(nil) + delegate?.titleFieldFinishedEditing(tag: id, + text: titleField.stringValue) } func controlTextDidChange(_ obj: Notification) { @@ -95,8 +102,6 @@ class MyTableCellView: NSTableCellView, NSTextFieldDelegate { { if commandSelector == #selector(NSResponder.insertNewline(_:)) { stopEditing() - delegate?.titleFieldFinishedEditing(tag: id, - text: titleField.stringValue) return true } else if commandSelector == #selector(NSResponder.insertTab(_:)) { return true @@ -104,4 +109,8 @@ class MyTableCellView: NSTableCellView, NSTextFieldDelegate { return false } + + func lostFocus() { + stopEditing() + } } diff --git a/src/PopoverPanel.swift b/src/PopoverPanel.swift index f5e403d..870c2ee 100644 --- a/src/PopoverPanel.swift +++ b/src/PopoverPanel.swift @@ -1,13 +1,7 @@ import Cocoa import Carbon -import OSLog class PopoverPanel: NSPanel { - fileprivate static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: PopoverPanel.self) - ) - override var canBecomeKey: Bool { true } init(viewController: NSViewController) { diff --git a/src/ProgramsTableView.swift b/src/ProgramsTableView.swift new file mode 100644 index 0000000..0338ead --- /dev/null +++ b/src/ProgramsTableView.swift @@ -0,0 +1,5 @@ +import AppKit + +final class ProgramsTableView: NSTableView { + override var acceptsFirstResponder: Bool { false } +} diff --git a/src/SearchViewController.swift b/src/SearchViewController.swift index df1008d..57ec71c 100644 --- a/src/SearchViewController.swift +++ b/src/SearchViewController.swift @@ -1,15 +1,9 @@ import AppKit import Carbon -import OSLog class SearchViewController: NSViewController, NSTextFieldDelegate, NSPopoverDelegate, NSTableViewDataSource, NSTableViewDelegate { - fileprivate static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: SearchViewController.self) - ) - private var keyboardEvents: EventMonitor? private var foundProgram: Program? = nil @@ -65,8 +59,8 @@ class SearchViewController: NSViewController, NSTextFieldDelegate, return scroll }() - private var programsTableView: MyNSTableView = { - let table = MyNSTableView() + private var programsTableView: ProgramsTableView = { + let table = ProgramsTableView() table.style = NSTableView.Style.plain table.backgroundColor = .clear @@ -262,9 +256,9 @@ class SearchViewController: NSViewController, NSTextFieldDelegate, configuration: config) { [weak self] application, error in if let error = error { - Self.logger.debug("\(error.localizedDescription)") + print("\(error.localizedDescription)") } else { - Self.logger.debug("Program opened successfully") + print("Program opened successfully") // NOTE: This needs a window! Do not just copy-paste // this block elsewhere. DispatchQueue.main.async { @@ -384,7 +378,3 @@ class SearchViewController: NSViewController, NSTextFieldDelegate, return cell } } - -final class MyNSTableView: NSTableView { - override var acceptsFirstResponder: Bool { false } -} diff --git a/src/SettingsViewController.swift b/src/SettingsViewController.swift index 8a88faf..eb3942c 100644 --- a/src/SettingsViewController.swift +++ b/src/SettingsViewController.swift @@ -1,17 +1,11 @@ import AppKit import Carbon import ServiceManagement -import OSLog class SettingsViewController: NSViewController, NSTextFieldDelegate, KeyDetectorButtonDelegate, NSTableViewDataSource, NSTableViewDelegate, - MyTableCellViewDelegate + PathsTableCellViewDelegate { - fileprivate static let logger = Logger( - subsystem: Bundle.main.bundleIdentifier!, - category: String(describing: SettingsViewController.self) - ) - private var recording = false // NOTE: This is the default shortcut. If you were to change it, don't @@ -133,7 +127,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, table.doubleAction = #selector(editItem) table.headerView = nil - table.allowsMultipleSelection = true + table.allowsMultipleSelection = false table.allowsColumnReordering = false table.allowsColumnResizing = false table.allowsColumnSelection = false @@ -260,7 +254,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, equalTo: shortcutsLabel.leadingAnchor), tableScrollView.widthAnchor.constraint(equalToConstant: 350), - tableScrollView.heightAnchor.constraint(equalToConstant: 100), + tableScrollView.heightAnchor.constraint(equalToConstant: 150), tableScrollView.topAnchor.constraint( equalTo: pathsLabel.bottomAnchor), tableScrollView.leadingAnchor.constraint( @@ -336,6 +330,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, modifiers = mods } + pathsTableView.reloadData() syncModifierButtons() launchAtLoginStatus() } @@ -355,6 +350,7 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, UserDefaults.standard.set(keyCode, forKey: "keyCode") UserDefaults.standard.set(modifiers, forKey: "keyModifiers") + PathManager.shared.removeEmpty() PathManager.shared.savePaths() PathManager.shared.rebuildIndex() } @@ -429,9 +425,9 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, } private func syncModifierButtons() { - ctrlButton.state = .off - cmdButton.state = .off - optButton.state = .off + ctrlButton.state = .off + cmdButton.state = .off + optButton.state = .off shiftButton.state = .off if modifiers & controlKey != 0 { @@ -454,29 +450,30 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, @objc private func affectPaths(_ sender: NSSegmentedControl) { - // PERF: All of this could be written better. let selectedSegment = sender.selectedSegment switch selectedSegment { case 0: - PathManager.shared.addPath("") - pathsTableView.reloadData() - - let row = PathManager.shared.userPaths.count-1 + // NOTE: Seems a bit error prone. + var row = PathManager.shared.userPaths.count-1 + if !PathManager.shared.userPaths[row].isEmpty { + row += 1 + PathManager.shared.addPath("") + pathsTableView.insertRows(at: IndexSet(integer: row), + withAnimation: []) + } + pathsTableView.scrollRowToVisible(row) pathsTableView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) - pathsTableView.scrollRowToVisible(row) (pathsTableView.view(atColumn: 0, row: row, - makeIfNecessary: false) as? MyTableCellView)? + makeIfNecessary: false) as? PathsTableCellView)? .startEditing() break case 1: - var toRemove: [String] = [] - for row in pathsTableView.selectedRowIndexes { - toRemove.append(PathManager.shared.userPaths[row]) + if pathsTableView.selectedRow > -1 { + PathManager.shared.userPaths + .remove(at: pathsTableView.selectedRow) + pathsTableView.reloadData() } - PathManager.shared.userPaths.removeAll( - where: { toRemove.contains($0) }) - pathsTableView.reloadData() break default: break @@ -492,19 +489,19 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, if let cell = pathsTableView.view(atColumn: 0, row: pathsTableView.clickedRow, - makeIfNecessary: false) as? MyTableCellView + makeIfNecessary: false) as? PathsTableCellView { cell.startEditing() } } func titleFieldFinishedEditing(tag: Int, text: String) { - PathManager.shared.userPaths[tag] = text - if PathManager.shared.userPaths[tag].isEmpty { + if text.isEmpty { PathManager.shared.userPaths.remove(at: tag) - pathsTableView.reloadData() + } else { + PathManager.shared.userPaths[tag] = text } - pathsTableView.deselectAll(nil) + pathsTableView.reloadData() } func titleFieldTextChanged(tag: Int, text: String) { @@ -543,20 +540,13 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, { let rect = NSRect(x: 0, y: 0, width: tableColumn!.width, height: 20) - let cell = MyTableCellView(frame: rect) + let cell = PathsTableCellView(frame: rect) cell.titleField.stringValue = PathManager.shared.userPaths[row] cell.delegate = self cell.id = row - return cell } func tableViewSelectionDidChange(_ notification: Notification) { -/* - let selectedRow = tableView.selectedRow - if selectedRow >= 0 { - print("Selected: \(items[selectedRow])") - } -*/ } }