1
1
mirror of https://github.com/qvacua/vimr.git synced 2024-11-24 19:47:41 +03:00
vimr/VimR/GeneralPrefPane.swift

304 lines
12 KiB
Swift
Raw Normal View History

2016-08-14 15:29:50 +03:00
/**
* Tae Won Ha - http://taewon.de - @hataewon
* See LICENSE
*/
import Cocoa
import PureLayout
import RxSwift
2016-11-19 15:29:18 +03:00
struct GeneralPrefData: Equatable, StandardPrefData {
2016-11-19 15:29:18 +03:00
fileprivate static let openNewWindowWhenLaunching = "open-new-window-when-launching"
fileprivate static let openNewWindowOnReactivation = "open-new-window-on-reactivation"
fileprivate static let ignorePatterns = "ignore-patterns"
fileprivate static let defaultIgnorePatterns = Set(
[ "*/.git", "*.o", "*.d", "*.dia" ].map(FileItemIgnorePattern.init)
)
static func ==(left: GeneralPrefData, right: GeneralPrefData) -> Bool {
return left.openNewWindowWhenLaunching == right.openNewWindowWhenLaunching
&& left.openNewWindowOnReactivation == right.openNewWindowOnReactivation
&& left.ignorePatterns == right.ignorePatterns
}
static let `default` = GeneralPrefData(openNewWindowWhenLaunching: true,
openNewWindowOnReactivation: true,
ignorePatterns: GeneralPrefData.defaultIgnorePatterns)
var openNewWindowWhenLaunching: Bool
var openNewWindowOnReactivation: Bool
var ignorePatterns: Set<FileItemIgnorePattern>
2016-08-14 15:29:50 +03:00
2016-11-19 15:29:18 +03:00
init(openNewWindowWhenLaunching: Bool,
openNewWindowOnReactivation: Bool,
ignorePatterns: Set<FileItemIgnorePattern>)
{
self.openNewWindowWhenLaunching = openNewWindowWhenLaunching
self.openNewWindowOnReactivation = openNewWindowOnReactivation
self.ignorePatterns = ignorePatterns
}
init?(dict: [String: Any]) {
guard let openNewWinWhenLaunching = PrefUtils.bool(from: dict, for: GeneralPrefData.openNewWindowWhenLaunching),
let openNewWinOnReactivation = PrefUtils.bool(from: dict, for: GeneralPrefData.openNewWindowOnReactivation),
let ignorePatternsStr = dict[GeneralPrefData.ignorePatterns] as? String
else {
return nil
}
self.init(openNewWindowWhenLaunching: openNewWinWhenLaunching,
openNewWindowOnReactivation: openNewWinOnReactivation,
ignorePatterns: PrefUtils.ignorePatterns(fromString: ignorePatternsStr))
}
func dict() -> [String: Any] {
return [
GeneralPrefData.openNewWindowWhenLaunching: self.openNewWindowWhenLaunching,
GeneralPrefData.openNewWindowOnReactivation: self.openNewWindowOnReactivation,
GeneralPrefData.ignorePatterns: PrefUtils.ignorePatternString(fromSet: self.ignorePatterns),
]
}
2016-08-14 19:59:00 +03:00
}
class GeneralPrefPane: PrefPane, NSTextFieldDelegate {
2016-08-14 15:29:50 +03:00
2016-09-24 17:35:27 +03:00
override var displayName: String {
return "General"
}
2016-09-10 22:46:43 +03:00
override var pinToContainer: Bool {
return true
}
2016-09-25 18:50:33 +03:00
fileprivate var data: GeneralPrefData
2016-08-14 16:38:41 +03:00
2016-09-25 18:50:33 +03:00
fileprivate let openWhenLaunchingCheckbox = NSButton(forAutoLayout: ())
fileprivate let openOnReactivationCheckbox = NSButton(forAutoLayout: ())
fileprivate let ignoreField = NSTextField(forAutoLayout: ())
2016-08-14 15:29:50 +03:00
init(source: Observable<Any>, initialData: GeneralPrefData) {
2016-08-14 19:59:00 +03:00
self.data = initialData
2016-08-14 15:29:50 +03:00
super.init(source: source)
2016-09-11 15:28:56 +03:00
self.updateViews(newData: initialData)
2016-08-14 15:29:50 +03:00
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func addViews() {
2016-08-25 10:27:59 +03:00
let paneTitle = self.paneTitleTextField(title: "General")
2016-08-14 15:29:50 +03:00
2016-08-25 10:27:59 +03:00
let openUntitledWindowTitle = self.titleTextField(title: "Open Untitled Window:")
2016-08-14 16:38:41 +03:00
self.configureCheckbox(button: self.openWhenLaunchingCheckbox,
2016-09-24 17:31:14 +03:00
title: "On launch",
2016-08-14 16:38:41 +03:00
action: #selector(GeneralPrefPane.openUntitledWindowWhenLaunchingAction(_:)))
self.configureCheckbox(button: self.openOnReactivationCheckbox,
2016-09-24 17:31:14 +03:00
title: "On re-activation",
2016-09-11 15:28:56 +03:00
action: #selector(GeneralPrefPane.openUntitledWindowOnReactivationAction(_:)))
2016-08-14 16:01:28 +03:00
2016-08-14 16:38:41 +03:00
let whenLaunching = self.openWhenLaunchingCheckbox
let onReactivation = self.openOnReactivationCheckbox
2016-09-10 22:46:43 +03:00
let ignoreListTitle = self.titleTextField(title: "Files To Ignore:")
2016-09-11 15:28:56 +03:00
let ignoreField = self.ignoreField
2016-10-27 00:37:51 +03:00
NotificationCenter.default.addObserver(forName: NSNotification.Name.NSControlTextDidEndEditing,
object: ignoreField,
queue: nil)
{ [unowned self] _ in
self.ignorePatternsAction()
}
2016-09-10 22:46:43 +03:00
let ignoreInfo = self.infoTextField(text: "")
ignoreInfo.attributedStringValue = self.ignoreInfoText()
2016-08-25 10:27:59 +03:00
let cliToolTitle = self.titleTextField(title: "CLI Tool:")
let cliToolButton = NSButton(forAutoLayout: ())
2016-09-24 17:31:14 +03:00
cliToolButton.title = "Copy 'vimr' CLI Tool..."
2016-09-25 18:50:33 +03:00
cliToolButton.bezelStyle = .rounded
cliToolButton.isBordered = true
cliToolButton.setButtonType(.momentaryPushIn)
2016-08-25 10:27:59 +03:00
cliToolButton.target = self
cliToolButton.action = #selector(GeneralPrefPane.copyCliTool(_:))
2016-09-10 22:46:43 +03:00
let cliToolInfo = self.infoTextField(
text: "Put the executable 'vimr' in your $PATH and execute 'vimr -h' for help."
)
2016-08-14 16:38:41 +03:00
2016-08-25 10:27:59 +03:00
self.addSubview(paneTitle)
2016-08-14 16:01:28 +03:00
self.addSubview(openUntitledWindowTitle)
2016-08-14 16:38:41 +03:00
self.addSubview(whenLaunching)
self.addSubview(onReactivation)
2016-09-10 22:46:43 +03:00
self.addSubview(ignoreListTitle)
self.addSubview(ignoreField)
self.addSubview(ignoreInfo)
2016-08-25 10:27:59 +03:00
self.addSubview(cliToolTitle)
self.addSubview(cliToolButton)
self.addSubview(cliToolInfo)
2016-08-14 16:01:28 +03:00
2016-09-25 18:50:33 +03:00
paneTitle.autoPinEdge(toSuperviewEdge: .top, withInset: 18)
paneTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
paneTitle.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
2016-08-14 16:01:28 +03:00
2016-09-25 18:50:33 +03:00
openUntitledWindowTitle.autoAlignAxis(.baseline, toSameAxisOf: whenLaunching, withOffset: 0)
openUntitledWindowTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18)
2016-08-14 16:01:28 +03:00
2016-09-25 18:50:33 +03:00
whenLaunching.autoPinEdge(.top, to: .bottom, of: paneTitle, withOffset: 18)
whenLaunching.autoPinEdge(.left, to: .right, of: openUntitledWindowTitle, withOffset: 5)
whenLaunching.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
2016-08-14 16:38:41 +03:00
2016-09-25 18:50:33 +03:00
onReactivation.autoPinEdge(.top, to: .bottom, of: whenLaunching, withOffset: 5)
onReactivation.autoPinEdge(.left, to: .left, of: whenLaunching)
onReactivation.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
2016-09-10 22:46:43 +03:00
2016-09-25 18:50:33 +03:00
ignoreListTitle.autoAlignAxis(.baseline, toSameAxisOf: ignoreField)
ignoreListTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
ignoreListTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
2016-09-10 22:46:43 +03:00
2016-09-25 18:50:33 +03:00
ignoreField.autoPinEdge(.top, to: .bottom, of: onReactivation, withOffset: 18)
ignoreField.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
ignoreField.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
2016-09-10 22:46:43 +03:00
2016-09-25 18:50:33 +03:00
ignoreInfo.autoPinEdge(.top, to: .bottom, of: ignoreField, withOffset: 5)
ignoreInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18)
ignoreInfo.autoPinEdge(.left, to: .right, of: ignoreListTitle, withOffset: 5)
2016-08-25 10:27:59 +03:00
2016-09-25 18:50:33 +03:00
cliToolTitle.autoAlignAxis(.baseline, toSameAxisOf: cliToolButton)
cliToolTitle.autoPinEdge(toSuperviewEdge: .left, withInset: 18, relation: .greaterThanOrEqual)
cliToolTitle.autoPinEdge(.right, to: .right, of: openUntitledWindowTitle)
2016-08-25 10:27:59 +03:00
2016-09-25 18:50:33 +03:00
cliToolButton.autoPinEdge(.top, to: .bottom, of: ignoreInfo, withOffset: 18)
cliToolButton.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
cliToolButton.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
2016-08-25 10:27:59 +03:00
2016-09-25 18:50:33 +03:00
cliToolInfo.autoPinEdge(.top, to: .bottom, of: cliToolButton, withOffset: 5)
cliToolInfo.autoPinEdge(toSuperviewEdge: .right, withInset: 18, relation: .greaterThanOrEqual)
cliToolInfo.autoPinEdge(.left, to: .right, of: cliToolTitle, withOffset: 5)
2016-08-25 10:27:59 +03:00
2016-08-14 22:46:03 +03:00
self.openWhenLaunchingCheckbox.boolState = self.data.openNewWindowWhenLaunching
self.openOnReactivationCheckbox.boolState = self.data.openNewWindowOnReactivation
2016-08-14 15:29:50 +03:00
}
2016-09-25 18:50:33 +03:00
override func subscription(source: Observable<Any>) -> Disposable {
2016-08-14 15:29:50 +03:00
return source
2016-08-14 22:46:03 +03:00
.filter { $0 is PrefData }
.map { ($0 as! PrefData).general }
2016-08-14 19:59:00 +03:00
.filter { [unowned self] data in data != self.data }
2016-09-25 19:10:07 +03:00
.subscribe(onNext: { [unowned self] data in
2016-09-11 15:28:56 +03:00
self.updateViews(newData: data)
self.data = data
2016-09-25 19:10:07 +03:00
})
2016-09-11 15:28:56 +03:00
}
override func windowWillClose() {
self.ignorePatternsAction()
2016-09-11 15:28:56 +03:00
}
2016-09-25 18:50:33 +03:00
fileprivate func set(data: GeneralPrefData) {
2016-09-11 15:28:56 +03:00
self.data = data
self.publish(event: data)
2016-08-14 15:29:50 +03:00
}
2016-08-14 16:01:28 +03:00
2016-09-25 18:50:33 +03:00
fileprivate func ignoreInfoText() -> NSAttributedString {
let font = NSFont.systemFont(ofSize: NSFont.smallSystemFontSize())
2016-09-11 15:28:56 +03:00
let attrs = [
NSFontAttributeName: font,
2016-09-25 18:50:33 +03:00
NSForegroundColorAttributeName: NSColor.gray
2016-09-11 15:28:56 +03:00
]
2016-09-25 18:50:33 +03:00
let wikiUrl = URL(string: "https://github.com/qvacua/vimr/wiki")!
2016-09-10 22:46:43 +03:00
let linkStr = NSAttributedString.link(withUrl: wikiUrl, text: "VimR Wiki", font: font)
2016-09-24 17:31:14 +03:00
let str = "Comma-separated list of ignore patterns\n"
2016-10-22 00:01:25 +03:00
+ "Matching files will be ignored in \"Open Quickly\" and the file browser.\n"
2016-09-10 22:46:43 +03:00
+ "Example: */.git, */node_modules\n"
2016-09-24 17:31:14 +03:00
+ "For detailed information see "
let ignoreInfoStr = NSMutableAttributedString(string:str, attributes:attrs)
2016-09-25 18:50:33 +03:00
ignoreInfoStr.append(linkStr)
ignoreInfoStr.append(NSAttributedString(string: ".", attributes: attrs))
2016-09-10 22:46:43 +03:00
return ignoreInfoStr
}
2016-09-25 18:50:33 +03:00
fileprivate func updateViews(newData: GeneralPrefData) {
2016-09-11 15:28:56 +03:00
self.openWhenLaunchingCheckbox.boolState = newData.openNewWindowWhenLaunching
self.openOnReactivationCheckbox.boolState = newData.openNewWindowOnReactivation
self.ignoreField.stringValue = PrefUtils.ignorePatternString(fromSet: newData.ignorePatterns)
2016-08-14 16:01:28 +03:00
}
}
// MARK: - Actions
extension GeneralPrefPane {
2016-08-25 10:27:59 +03:00
2016-09-25 18:50:33 +03:00
func copyCliTool(_ sender: NSButton) {
2016-08-25 10:27:59 +03:00
let panel = NSOpenPanel()
panel.canChooseFiles = false
panel.canChooseDirectories = true
2016-09-25 18:50:33 +03:00
panel.beginSheetModal(for: self.window!) { result in
2016-08-25 10:27:59 +03:00
guard result == NSFileHandlingPanelOKButton else {
return
}
2016-09-25 18:50:33 +03:00
guard let vimrUrl = Bundle.main.url(forResource: "vimr", withExtension: nil) else {
2016-08-25 10:27:59 +03:00
self.alert(title: "Something Went Wrong.",
info: "The CLI tool 'vimr' could not be found. Please re-download VimR and try again.")
return
}
2016-09-25 18:50:33 +03:00
guard let targetUrl = panel.url?.appendingPathComponent("vimr") else {
2016-08-25 10:27:59 +03:00
self.alert(title: "Something Went Wrong.",
info: "The target directory could not be determined. Please try again with a different directory.")
return
}
do {
2016-09-25 18:50:33 +03:00
try FileManager.default.copyItem(at: vimrUrl, to: targetUrl)
} catch let err as NSError {
self.alert(title: "Error copying 'vimr'", info: err.localizedDescription)
2016-08-25 10:27:59 +03:00
}
}
}
2016-08-14 16:01:28 +03:00
2016-09-25 18:50:33 +03:00
func openUntitledWindowWhenLaunchingAction(_ sender: NSButton) {
2016-09-11 15:28:56 +03:00
self.set(data: GeneralPrefData(
openNewWindowWhenLaunching: self.openWhenLaunchingCheckbox.boolState,
openNewWindowOnReactivation: self.data.openNewWindowOnReactivation,
ignorePatterns: self.data.ignorePatterns)
)
2016-08-14 16:01:28 +03:00
}
2016-09-25 18:50:33 +03:00
func openUntitledWindowOnReactivationAction(_ sender: NSButton) {
2016-09-11 15:28:56 +03:00
self.set(data: GeneralPrefData(
openNewWindowWhenLaunching: self.data.openNewWindowWhenLaunching,
openNewWindowOnReactivation: self.openOnReactivationCheckbox.boolState,
ignorePatterns: self.data.ignorePatterns)
)
2016-08-14 16:01:28 +03:00
}
2016-09-11 15:28:56 +03:00
2016-09-25 18:50:33 +03:00
fileprivate func ignorePatternsAction() {
let patterns = PrefUtils.ignorePatterns(fromString: self.ignoreField.stringValue)
if patterns == self.data.ignorePatterns {
return
}
2016-09-11 15:28:56 +03:00
self.set(data: GeneralPrefData(
openNewWindowWhenLaunching: self.data.openNewWindowWhenLaunching,
openNewWindowOnReactivation: self.data.openNewWindowOnReactivation,
ignorePatterns: patterns)
)
}
2016-09-25 18:50:33 +03:00
fileprivate func alert(title: String, info: String) {
2016-08-25 10:27:59 +03:00
let alert = NSAlert()
2016-09-25 18:50:33 +03:00
alert.alertStyle = .warning
2016-08-25 10:27:59 +03:00
alert.messageText = title
alert.informativeText = info
alert.runModal()
}
2016-08-14 15:29:50 +03:00
}