passepartout-apple/Passepartout/App/macOS/Scenes/OrganizerProfileTableView.swift
Davide De Rosa 8833c4dbab Update TunnelKit with BoringSSL
- Optimize package granularity and imports
- Adjust targets to smaller TunnelKit components
- Raise iOS target to 13
- Drop support for TLS security level
2021-11-11 15:45:09 +01:00

180 lines
5.4 KiB
Swift

//
// OrganizerProfileTableView.swift
// Passepartout
//
// Created by Davide De Rosa on 6/23/19.
// Copyright (c) 2021 Davide De Rosa. All rights reserved.
//
// https://github.com/passepartoutvpn
//
// This file is part of Passepartout.
//
// Passepartout is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Passepartout is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Passepartout. If not, see <http://www.gnu.org/licenses/>.
//
import Cocoa
import PassepartoutCore
protocol OrganizerProfileTableViewDelegate: AnyObject {
func profileTableViewDidRequestAdd(_ profileTableView: OrganizerProfileTableView, sender: NSView)
func profileTableView(_ profileTableView: OrganizerProfileTableView, didRequestRemove profile: ConnectionProfile)
func profileTableView(_ profileTableView: OrganizerProfileTableView, didRequestRename profile: HostConnectionProfile)
}
class OrganizerProfileTableView: NSView {
@IBOutlet private weak var tableView: NSTableView!
@IBOutlet private weak var buttonAdd: NSButton!
@IBOutlet private weak var buttonRemove: NSButton!
@IBOutlet private weak var buttonRename: NSButton!
private let service = TransientStore.shared.service
var rows: [ConnectionProfile] = []
var selectedRow: Int?
var selectionBlock: ((ConnectionProfile) -> Void)?
var deselectionBlock: (() -> Void)?
private var isAddEnabled: Bool {
get {
return buttonAdd.isEnabled
}
set {
buttonAdd.isEnabled = newValue
}
}
private var isRemoveEnabled: Bool {
get {
return buttonRemove.isEnabled
}
set {
buttonRemove.isEnabled = newValue
}
}
private var isRenameEnabled: Bool {
get {
return buttonRename.isEnabled
}
set {
buttonRename.isEnabled = newValue
}
}
weak var delegate: OrganizerProfileTableViewDelegate?
override func viewWillMove(toSuperview newSuperview: NSView?) {
super.viewWillMove(toSuperview: newSuperview)
buttonAdd.image = NSImage(named: NSImage.addTemplateName)
buttonRemove.image = NSImage(named: NSImage.removeTemplateName)
buttonRename.image = NSImage(named: NSImage.actionTemplateName)
}
func reloadData() {
tableView.reloadData()
if let i = selectedRow {
tableView.selectRowIndexes(IndexSet(integer: i), byExtendingSelection: false)
}
updateButtonsStatus()
}
// MARK: Actions
@IBAction private func addProfile(_ sender: Any?) {
delegate?.profileTableViewDidRequestAdd(self, sender: sender as! NSButton)
}
@IBAction private func removeProfile(_ sender: Any?) {
let index = tableView.selectedRow
guard index != -1 else {
return
}
delegate?.profileTableView(self, didRequestRemove: rows[index])
}
@IBAction private func renameProfile(_ sender: Any?) {
let index = tableView.selectedRow
guard index != -1 else {
return
}
guard let hostProfile = rows[index] as? HostConnectionProfile else {
return
}
delegate?.profileTableView(self, didRequestRename: hostProfile)
}
// MARK: Helpers
private func updateButtonsStatus() {
let index = tableView.selectedRow
guard index != -1 else {
isRemoveEnabled = false
isRenameEnabled = false
deselectionBlock?()
return
}
isRemoveEnabled = true
isRenameEnabled = (rows[index] as? HostConnectionProfile != nil)
}
}
class OrganizerProfileTableViewCell: NSTableCellView {
@IBOutlet private weak var imageActive: NSImageView?
override var objectValue: Any? {
didSet {
guard let objectValue = objectValue else {
return
}
guard let pair = objectValue as? (ConnectionService, ConnectionProfile) else {
fatalError("objectValue is not a (ConnectionService, ConnectionProfile)")
}
imageView?.image = pair.1.image
textField?.stringValue = pair.0.screenTitle(ProfileKey(pair.1))
// FIXME: active profile icon
imageActive?.image = NSImage(named: NSImage.menuOnStateTemplateName)
imageActive?.isHidden = !TransientStore.shared.service.isActiveProfile(pair.1)
}
}
}
extension OrganizerProfileTableView: NSTableViewDataSource, NSTableViewDelegate {
func numberOfRows(in tableView: NSTableView) -> Int {
return rows.count
}
func tableView(_ tableView: NSTableView, objectValueFor tableColumn: NSTableColumn?, row: Int) -> Any? {
return (service, rows[row])
}
func tableViewSelectionDidChange(_ notification: Notification) {
updateButtonsStatus()
let index = tableView.selectedRow
if index != -1 {
selectionBlock?(rows[index])
}
}
}