forked from I2P_Developers/i2p.i2p
Mac OS X Launcher: Adding user interface classes for the different Preferences views so far.
This commit is contained in:
@ -0,0 +1,17 @@
|
||||
//
|
||||
// AdvancedTableView.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 08/12/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
|
||||
class AdvancedTableView: NSTableView {
|
||||
override func viewWillDraw() {
|
||||
super.viewWillDraw()
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,94 @@
|
||||
//
|
||||
// PreferencesViewController+TableView.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 08/12/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
extension PreferencesViewController: NSTableViewDataSource {
|
||||
|
||||
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||
return Preferences.shared().count
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension PreferencesViewController: NSTableViewDelegate {
|
||||
|
||||
fileprivate enum CellIdentifiers {
|
||||
static let NameCell = "KeyColumnID"
|
||||
static let DefaultCell = "DefaultColumnID"
|
||||
static let ValueCell = "ValueColumnID"
|
||||
}
|
||||
|
||||
func tableViewDoubleClick(_ sender:AnyObject) {
|
||||
|
||||
// 1
|
||||
/*guard tableView.selectedRow >= 0,
|
||||
let item = Preferences.shared()[tableView.selectedRow] else {
|
||||
return
|
||||
}
|
||||
|
||||
if item.isFolder {
|
||||
// 2
|
||||
self.representedObject = item.url as Any
|
||||
}
|
||||
else {
|
||||
// 3
|
||||
NSWorkspace.shared().open(item.url as URL)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
func tableView(_ tableView: NSTableView, sortDescriptorsDidChange oldDescriptors: [NSSortDescriptor]) {
|
||||
// 1
|
||||
guard let sortDescriptor = tableView.sortDescriptors.first else {
|
||||
return
|
||||
}
|
||||
/*if let order = Directory.FileOrder(rawValue: sortDescriptor.key!) {
|
||||
// 2
|
||||
sortOrder = order
|
||||
sortAscending = sortDescriptor.ascending
|
||||
reloadFileList()
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||
|
||||
//var image: NSImage?
|
||||
var text: String = ""
|
||||
var cellIdentifier: String = ""
|
||||
|
||||
|
||||
// 1
|
||||
guard let item = Preferences.shared()[row] else {
|
||||
return nil
|
||||
}
|
||||
|
||||
// 2
|
||||
if tableColumn == tableView.tableColumns[0] {
|
||||
text = item.name!
|
||||
cellIdentifier = CellIdentifiers.NameCell
|
||||
} else if tableColumn == tableView.tableColumns[1] {
|
||||
text = "\(item.defaultValue!)"
|
||||
cellIdentifier = CellIdentifiers.DefaultCell
|
||||
} else if tableColumn == tableView.tableColumns[2] {
|
||||
let thing = (item.selectedValue ?? "none")
|
||||
text = "\(thing)"
|
||||
cellIdentifier = CellIdentifiers.ValueCell
|
||||
}
|
||||
|
||||
// 3
|
||||
if let cell = tableView.make(withIdentifier: cellIdentifier, owner: nil) as? NSTableCellView {
|
||||
cell.textField?.stringValue = text
|
||||
//cell.imageView?.image = image ?? nil
|
||||
return cell
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,257 @@
|
||||
//
|
||||
// PreferencesViewController.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 07/11/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
// Table view programming guide from Apple:
|
||||
// https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/TableView/Introduction/Introduction.html
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
|
||||
class PreferencesViewController: NSViewController {
|
||||
|
||||
enum ShowAsMode {
|
||||
case bothIcon
|
||||
case menubarIcon
|
||||
case dockIcon
|
||||
}
|
||||
|
||||
var changeDockMenubarIconTimer: Timer?
|
||||
|
||||
// MARK: - Advanced settings objects
|
||||
@IBOutlet weak var advPrefTableView: NSTableView!
|
||||
|
||||
// MARK: - Launcher settings objects
|
||||
@IBOutlet var radioDockIcon: NSButton?
|
||||
@IBOutlet var radioMenubarIcon: NSButton?
|
||||
@IBOutlet var radioBothIcon: NSButton?
|
||||
@IBOutlet var checkboxStartWithOSX: NSButton?
|
||||
@IBOutlet var checkboxStartFirefoxAlso: NSButton?
|
||||
|
||||
// MARK: - Router objects
|
||||
@IBOutlet var checkboxStartWithLauncher: NSButton?
|
||||
@IBOutlet var checkboxStopWithLauncher: NSButton?
|
||||
@IBOutlet var buttonResetRouterConfig: NSButton?
|
||||
|
||||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
self.preferredContentSize = NSMakeSize(self.view.frame.size.width, self.view.frame.size.height)
|
||||
|
||||
if (advPrefTableView != nil) {
|
||||
// For data feeding and view
|
||||
advPrefTableView.delegate = self
|
||||
advPrefTableView.dataSource = self
|
||||
|
||||
// Responding to Double-Click
|
||||
advPrefTableView.target = self
|
||||
advPrefTableView.doubleAction = #selector(tableViewDoubleClick(_:))
|
||||
|
||||
// Always redraw preference items which might have changed state since last draw.
|
||||
Preferences.shared().redrawPrefTableItems()
|
||||
|
||||
// For sorting
|
||||
advPrefTableView.tableColumns[0].sortDescriptorPrototype = NSSortDescriptor(key: "name", ascending: true)
|
||||
advPrefTableView.tableColumns[1].sortDescriptorPrototype = NSSortDescriptor(key: "defaultValue", ascending: true)
|
||||
advPrefTableView.tableColumns[2].sortDescriptorPrototype = NSSortDescriptor(key: "selectedValue", ascending: true)
|
||||
}
|
||||
|
||||
// Update radio buttons to reflect runtime/stored preferences
|
||||
self.updateRadioButtonEffect(mode: Preferences.shared().showAsIconMode, withSideEffect: false)
|
||||
|
||||
}
|
||||
|
||||
override func viewDidAppear() {
|
||||
super.viewDidAppear()
|
||||
|
||||
// Update window title
|
||||
self.parent?.view.window?.title = self.title!
|
||||
}
|
||||
|
||||
// MARK: - Router settings functions
|
||||
|
||||
@IBAction func checkboxStartRouterWithLauncherClicked(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case NSOnState:
|
||||
print("on")
|
||||
Preferences.shared().startRouterOnLauncherStart = true
|
||||
case NSOffState:
|
||||
print("off")
|
||||
Preferences.shared().startRouterOnLauncherStart = false
|
||||
case NSMixedState:
|
||||
print("mixed")
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func checkboxStopRouterWithLauncherClicked(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case NSOnState:
|
||||
print("on")
|
||||
Preferences.shared().stopRouterOnLauncherShutdown = true
|
||||
case NSOffState:
|
||||
print("off")
|
||||
Preferences.shared().stopRouterOnLauncherShutdown = false
|
||||
case NSMixedState:
|
||||
print("mixed")
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func buttonResetRouterConfigClicked(_ sender: Any) {
|
||||
// TODO: Add a modal dialog asking user if they are **really** sure
|
||||
}
|
||||
|
||||
// MARK: - Launcher settings functions
|
||||
|
||||
@IBAction func checkboxStartLauncherOnOSXStartupClicked(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case NSOnState:
|
||||
print("on")
|
||||
case NSOffState:
|
||||
print("off")
|
||||
case NSMixedState:
|
||||
print("mixed")
|
||||
default: break
|
||||
}
|
||||
}
|
||||
@IBAction func checkboxStartFirefoxAlsoAtLaunchClicked(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case NSOnState:
|
||||
print("on")
|
||||
case NSOffState:
|
||||
print("off")
|
||||
case NSMixedState:
|
||||
print("mixed")
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Radio buttons functions
|
||||
|
||||
func updateDockMenubarIcons(_ mode: ShowAsMode) -> Bool {
|
||||
// Update preferences with latest choise
|
||||
Preferences.shared().showAsIconMode = mode
|
||||
// Update runtime
|
||||
switch mode {
|
||||
case .bothIcon, .dockIcon:
|
||||
// Show dock icon
|
||||
print("Preferences: Update Dock Icon -> Show")
|
||||
if (!getDockIconStateIsShowing()) {
|
||||
return triggerDockIconShowHide(showIcon: true)
|
||||
}
|
||||
case .menubarIcon:
|
||||
// Hide dock icon
|
||||
print("Preferences: Update Dock Icon -> Hide")
|
||||
if (getDockIconStateIsShowing()) {
|
||||
return triggerDockIconShowHide(showIcon: false)
|
||||
}
|
||||
}
|
||||
// Note: In reality, this won't ever happen.
|
||||
// The switch statement above would return before this.
|
||||
return false
|
||||
}
|
||||
|
||||
func updateRadioButtonEffect(mode: ShowAsMode, withSideEffect: Bool = true) {
|
||||
changeDockMenubarIconTimer?.invalidate()
|
||||
|
||||
radioDockIcon?.state = NSOffState
|
||||
radioMenubarIcon?.state = NSOffState
|
||||
radioBothIcon?.state = NSOffState
|
||||
|
||||
switch mode {
|
||||
case .bothIcon:
|
||||
radioBothIcon?.state = NSOnState
|
||||
case .dockIcon:
|
||||
radioDockIcon?.state = NSOnState
|
||||
case .menubarIcon:
|
||||
radioMenubarIcon?.state = NSOnState
|
||||
}
|
||||
|
||||
if (withSideEffect) {
|
||||
if #available(OSX 10.12, *) {
|
||||
changeDockMenubarIconTimer = Timer.scheduledTimer(withTimeInterval: 0.3, repeats: false, block: { _ in
|
||||
// If we're on 10.12 or later
|
||||
self.updateDockMenubarIcons(mode)
|
||||
})
|
||||
} else {
|
||||
// Fallback on earlier versions
|
||||
self.updateDockMenubarIcons(mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@IBAction func radioBothIconSelected(_ sender: Any) {
|
||||
updateRadioButtonEffect(mode: ShowAsMode.bothIcon)
|
||||
}
|
||||
|
||||
@IBAction func radioDockIconOnlySelected(_ sender: Any) {
|
||||
updateRadioButtonEffect(mode: ShowAsMode.dockIcon)
|
||||
}
|
||||
|
||||
@IBAction func radioMenubarOnlySelected(_ sender: Any) {
|
||||
updateRadioButtonEffect(mode: ShowAsMode.menubarIcon)
|
||||
}
|
||||
|
||||
// MARK: - Triggers
|
||||
|
||||
func triggerDockIconHideShow(showIcon state: Bool) -> Bool {
|
||||
// Get transform state.
|
||||
var transformState: ProcessApplicationTransformState
|
||||
if state {
|
||||
transformState = ProcessApplicationTransformState(kProcessTransformToForegroundApplication)
|
||||
} else {
|
||||
transformState = ProcessApplicationTransformState(kProcessTransformToUIElementApplication)
|
||||
}
|
||||
|
||||
// Show / hide dock icon.
|
||||
var psn = ProcessSerialNumber(highLongOfPSN: 0, lowLongOfPSN: UInt32(kCurrentProcess))
|
||||
let transformStatus: OSStatus = TransformProcessType(&psn, transformState)
|
||||
return transformStatus == 0
|
||||
}
|
||||
|
||||
func triggerDockIconShowHide(showIcon state: Bool) -> Bool {
|
||||
var result: Bool
|
||||
if state {
|
||||
result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.regular)
|
||||
} else {
|
||||
result = NSApp.setActivationPolicy(NSApplicationActivationPolicy.accessory)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func getDockIconStateIsShowing() -> Bool {
|
||||
if NSApp.activationPolicy() == NSApplicationActivationPolicy.regular {
|
||||
return true
|
||||
} else {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Advanced
|
||||
|
||||
@IBAction func checkboxEnableAdvancedPreferencesClicked(_ sender: NSButton) {
|
||||
switch sender.state {
|
||||
case NSOnState:
|
||||
print("on")
|
||||
Preferences.shared().allowAdvancedPreferenceEdit = true
|
||||
case NSOffState:
|
||||
print("off")
|
||||
Preferences.shared().allowAdvancedPreferenceEdit = false
|
||||
case NSMixedState:
|
||||
print("mixed")
|
||||
default: break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// End of Class
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,24 @@
|
||||
//
|
||||
// PreferencesWindowController.swift
|
||||
// I2PLauncher
|
||||
//
|
||||
// Created by Mikal Villa on 07/11/2018.
|
||||
// Copyright © 2018 The I2P Project. All rights reserved.
|
||||
//
|
||||
|
||||
import Cocoa
|
||||
|
||||
class PreferencesWindowController: NSWindowController, NSWindowDelegate {
|
||||
|
||||
override func windowDidLoad() {
|
||||
super.windowDidLoad()
|
||||
|
||||
// Implement this method to handle any initialization after your window controller's window has been loaded from its nib file.
|
||||
}
|
||||
|
||||
func windowShouldClose(_ sender: NSWindow) -> Bool {
|
||||
self.window?.orderOut(sender)
|
||||
return false
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user