AVRSack/AVRsack/ASProjDoc.swift

660 lines
25 KiB
Swift
Raw Normal View History

2014-11-15 03:39:10 +00:00
//
2014-11-15 22:47:46 +00:00
// ASProjDoc.swift
2014-11-15 03:39:10 +00:00
// AVRsack
//
// Created by Matthias Neeracher on 11/15/14.
// Copyright (c) 2014 Aere Perennius. All rights reserved.
//
2014-12-07 05:20:57 +00:00
import Swift
2014-11-15 03:39:10 +00:00
import Cocoa
private var keyboardHandler : ACEKeyboardHandler = .Ace
2014-12-07 05:20:57 +00:00
func pushToFront(inout list: [String], front: String) {
let kMaxRecents = 8
if let existing = find(list, front) {
if existing == 0 {
return
} else {
list.removeAtIndex(existing)
}
} else if list.count >= kMaxRecents {
list.removeLast()
}
list.insert(front, atIndex: 0)
}
2015-01-12 00:53:35 +00:00
class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePanelDelegate {
2014-11-16 18:39:32 +00:00
@IBOutlet weak var editor : ACEView!
@IBOutlet weak var outline : NSOutlineView!
2014-12-07 05:20:57 +00:00
@IBOutlet weak var boardTool: NSPopUpButton!
@IBOutlet weak var progTool : NSPopUpButton!
@IBOutlet weak var portTool : NSPopUpButton!
2014-11-28 13:18:53 +00:00
let files = ASFileTree()
let builder = ASBuilder()
2014-11-16 18:39:32 +00:00
var mainEditor : ASFileNode?
var currentTheme : UInt = 0
var fontSize : UInt = 12
2014-12-29 06:35:07 +00:00
var themeObserver : AnyObject!
var serialObserver : AnyObject!
2014-12-10 02:51:26 +00:00
dynamic var board = "uno"
dynamic var programmer = "arduino"
dynamic var port : String = ""
2014-12-07 05:20:57 +00:00
var recentBoards = [String]()
var recentProgrammers = [String]()
2015-02-14 16:43:20 +00:00
var logModified = NSDate.distantPast() as! NSDate
2014-12-08 01:55:19 +00:00
var logSize = 0
2014-12-01 02:34:53 +00:00
var updateLogTimer : NSTimer?
2014-11-15 22:47:46 +00:00
2014-12-07 05:20:57 +00:00
let kVersionKey = "Version"
let kCurVersion = 1.0
let kFilesKey = "Files"
let kThemeKey = "Theme"
let kFontSizeKey = "FontSize"
let kBindingsKey = "Bindings"
let kBoardKey = "Board"
let kProgrammerKey = "Programmer"
let kPortKey = "Port"
let kRecentBoardsKey = "RecentBoards"
let kRecentProgrammersKey = "RecentProgrammers"
2014-11-17 01:29:55 +00:00
// MARK: Initialization / Finalization
2014-11-15 03:39:10 +00:00
override init() {
super.init()
let userDefaults = NSUserDefaults.standardUserDefaults()
if let themeName = userDefaults.stringForKey(kThemeKey) {
2014-12-31 03:16:43 +00:00
if let themeId = ACEView.themeIdByName(themeName) {
currentTheme = themeId
}
}
if let handlerName = userDefaults.stringForKey(kBindingsKey) {
2014-12-31 03:16:43 +00:00
if let handlerId = ACEView.handlerIdByName(handlerName) {
keyboardHandler = handlerId
}
}
2014-12-09 05:54:30 +00:00
fontSize = UInt(userDefaults.integerForKey(kFontSizeKey))
2014-12-07 05:20:57 +00:00
board = userDefaults.stringForKey(kBoardKey)!
programmer = userDefaults.stringForKey(kProgrammerKey)!
port = userDefaults.stringForKey(kPortKey)!
2015-02-14 16:43:20 +00:00
recentBoards = userDefaults.objectForKey(kRecentBoardsKey) as! [String]
recentProgrammers = userDefaults.objectForKey(kRecentProgrammersKey) as! [String]
2014-12-01 02:34:53 +00:00
2014-12-09 05:54:30 +00:00
var nc = NSNotificationCenter.defaultCenter()
themeObserver = nc.addObserverForName(kBindingsKey, object: nil, queue: nil, usingBlock: { (NSNotification) in
self.editor.setKeyboardHandler(keyboardHandler)
})
serialObserver = nc.addObserverForName(kASSerialPortsChanged, object: nil, queue: nil, usingBlock: { (NSNotification) in
self.rebuildPortMenu()
})
2014-12-01 02:34:53 +00:00
updateLogTimer =
NSTimer.scheduledTimerWithTimeInterval(1.0, target: self, selector: "updateLog:", userInfo: nil, repeats: true)
2014-11-15 03:39:10 +00:00
}
override func finalize() {
saveCurEditor()
2014-12-29 06:35:07 +00:00
NSNotificationCenter.defaultCenter().removeObserver(themeObserver)
NSNotificationCenter.defaultCenter().removeObserver(serialObserver)
}
2014-11-15 03:39:10 +00:00
override func windowControllerDidLoadNib(aController: NSWindowController) {
super.windowControllerDidLoadNib(aController)
editor.setShowPrintMargin(false)
editor.setTheme(currentTheme)
editor.setKeyboardHandler(keyboardHandler)
editor.setFontSize(fontSize)
2014-11-16 18:39:32 +00:00
outline.setDataSource(files)
files.apply() { node in
if let group = node as? ASFileGroup {
if group.expanded {
self.outline.expandItem(node)
}
}
}
outlineViewSelectionDidChange(NSNotification(name: "", object: nil))
2014-12-07 05:20:57 +00:00
menuNeedsUpdate(boardTool.menu!)
menuNeedsUpdate(progTool.menu!)
2014-12-09 05:54:30 +00:00
rebuildPortMenu()
updateChangeCount(.ChangeCleared)
2014-11-15 03:39:10 +00:00
}
override class func autosavesInPlace() -> Bool {
return true
}
override var windowNibName: String? {
// Returns the nib file name of the document
// If you need to use a subclass of NSWindowController or if your document supports multiple NSWindowControllers, you should remove this property and override -makeWindowControllers instead.
2014-11-15 22:47:46 +00:00
return "ASProjDoc"
2014-11-15 03:39:10 +00:00
}
2014-11-17 01:29:55 +00:00
// MARK: Load / Save
func saveCurEditor() {
if let file = (mainEditor as? ASFileItem) {
editor.string().writeToURL(file.url, atomically: true, encoding: NSUTF8StringEncoding, error: nil)
}
}
2014-11-15 03:39:10 +00:00
override func dataOfType(typeName: String, error outError: NSErrorPointer) -> NSData? {
let data = [kVersionKey: kCurVersion,
kThemeKey: ACEThemeNames.nameForTheme(currentTheme),
kFontSizeKey: fontSize,
2014-12-07 05:20:57 +00:00
kFilesKey: files.propertyList(),
kBoardKey: board,
kProgrammerKey: programmer,
kPortKey: port
]
2014-11-17 01:29:55 +00:00
return NSPropertyListSerialization.dataFromPropertyList(data, format: .XMLFormat_v1_0, errorDescription: nil)
2014-11-15 03:39:10 +00:00
}
2015-01-12 03:24:29 +00:00
func updateProjectURL() {
files.setProjectURL(fileURL!)
builder.setProjectURL(fileURL!)
}
2014-11-16 18:39:32 +00:00
func importProject(url: NSURL, error outError: NSErrorPointer) -> Bool {
let existingProject = url.URLByAppendingPathComponent(url.lastPathComponent!+".avrsackproj")
2014-11-16 18:39:32 +00:00
if existingProject.checkResourceIsReachableAndReturnError(nil) {
fileURL = existingProject
return readFromURL(existingProject, ofType:"Project", error:outError)
}
let filesInProject =
NSFileManager.defaultManager().contentsOfDirectoryAtURL(url, includingPropertiesForKeys: nil,
2015-02-14 16:43:20 +00:00
options: .SkipsHiddenFiles, error: nil) as! [NSURL]
2015-01-12 03:24:29 +00:00
updateProjectURL()
2014-11-16 18:39:32 +00:00
for file in filesInProject {
2015-02-14 16:43:20 +00:00
files.addFileURL(file)
2014-11-16 18:39:32 +00:00
}
return true
}
override func readFromURL(url: NSURL, ofType typeName: String, error outError: NSErrorPointer) -> Bool {
var success : Bool = false
if typeName == "Arduino Source File" {
let projectURL = url.URLByDeletingPathExtension!.URLByAppendingPathExtension("avrsackproj")
success = importProject(url.URLByDeletingLastPathComponent!, error: outError)
2014-11-17 01:29:55 +00:00
if success {
fileURL = projectURL
success = writeToURL(projectURL, ofType: "Project", forSaveOperation: .SaveAsOperation, originalContentsURL: nil, error: outError)
}
2014-11-16 18:39:32 +00:00
} else {
2014-11-17 01:29:55 +00:00
success = super.readFromURL(url, ofType: typeName, error: outError)
}
2014-11-16 18:39:32 +00:00
return success
}
2014-11-17 01:29:55 +00:00
override func readFromData(data: NSData, ofType typeName: String, error outError: NSErrorPointer) -> Bool {
2015-02-14 16:43:20 +00:00
if typeName != ("Project" as String) {
2014-11-17 01:29:55 +00:00
return false
}
2015-01-12 03:24:29 +00:00
updateProjectURL()
2015-02-14 16:43:20 +00:00
let projectData : NSDictionary = NSPropertyListSerialization.propertyListFromData(data, mutabilityOption: .Immutable, format: nil, errorDescription: nil) as! NSDictionary
let projectVersion = projectData[kVersionKey] as! Double
2014-11-17 01:29:55 +00:00
assert(projectVersion <= floor(kCurVersion+1.0), "Project version too new for this app")
2015-02-14 16:43:20 +00:00
if let themeName = projectData[kThemeKey] as? String {
2014-12-31 03:16:43 +00:00
if let themeId = ACEView.themeIdByName(themeName) {
currentTheme = themeId
}
}
if let fontSz = projectData[kFontSizeKey] as? Int {
fontSize = UInt(fontSz)
}
2015-02-14 16:43:20 +00:00
files.readPropertyList(projectData[kFilesKey] as! NSDictionary)
2014-12-07 05:20:57 +00:00
board = (projectData[kBoardKey] as? String) ?? board
programmer = (projectData[kProgrammerKey] as? String) ?? programmer
port = (projectData[kPortKey] as? String) ?? port
recentBoards = (projectData[kRecentBoardsKey] as? [String]) ?? recentBoards
recentProgrammers = (projectData[kRecentProgrammersKey] as? [String]) ?? recentProgrammers
updateChangeCount(.ChangeCleared)
2014-11-17 01:29:55 +00:00
return true
}
2014-12-01 02:34:53 +00:00
func updateLog(AnyObject?) {
if let logNode = mainEditor as? ASLogNode {
let url = fileURL!.URLByDeletingLastPathComponent?.URLByAppendingPathComponent(logNode.path)
if url == nil {
return
}
var modified : AnyObject?
2014-12-08 01:55:19 +00:00
var size : AnyObject?
if (!url!.getResourceValue(&modified, forKey:NSURLAttributeModificationDateKey, error:nil)) {
return
}
if (!url!.getResourceValue(&size, forKey:NSURLFileSizeKey, error:nil)) {
return
}
2015-02-14 16:43:20 +00:00
if (modified as! NSDate).compare(logModified) == .OrderedDescending || (size as! Int) != logSize {
2014-12-08 01:55:19 +00:00
var enc : UInt = 0
2015-02-14 16:43:20 +00:00
let newText = NSString(contentsOfURL:url!, usedEncoding:&enc, error:nil) as! String
2014-12-08 01:55:19 +00:00
editor.setString(newText)
editor.gotoLine(1000000000, column: 0, animated: true)
2015-02-14 16:43:20 +00:00
logModified = modified as! NSDate
logSize = size as! Int
2014-12-01 02:34:53 +00:00
}
}
}
func selectNode(selection: ASFileNode?) {
2014-11-16 18:39:32 +00:00
if selection !== mainEditor {
saveCurEditor()
}
if let file = (selection as? ASFileItem) {
var enc : UInt = 0
2015-02-14 16:43:20 +00:00
editor.setString(NSString(contentsOfURL:file.url, usedEncoding:&enc, error:nil) as! String)
2014-11-16 18:39:32 +00:00
editor.setMode(UInt(file.type.aceMode))
editor.alphaValue = 1.0
2014-12-01 02:34:53 +00:00
mainEditor = selection
} else if let log = (selection as? ASLogNode) {
editor.setString("")
2014-12-31 03:16:43 +00:00
editor.setMode(UInt(ACEModeText))
2014-12-01 02:34:53 +00:00
editor.alphaValue = 0.8
2015-02-14 16:43:20 +00:00
logModified = NSDate.distantPast() as! NSDate
2014-12-08 01:55:19 +00:00
logSize = -1
2014-12-01 02:34:53 +00:00
mainEditor = selection
updateLog(nil)
} else {
editor.alphaValue = 0.0
2014-11-16 18:39:32 +00:00
}
}
2014-12-09 05:13:45 +00:00
func selectNodeInOutline(selection: ASFileNode) {
let selectedIndexes = NSIndexSet(index: outline.rowForItem(selection))
outline.selectRowIndexes(selectedIndexes, byExtendingSelection: false)
}
2015-01-12 00:53:35 +00:00
func selectedFiles() -> [ASFileItem] {
var selection = [ASFileItem]()
outline.selectedRowIndexes.enumerateIndexesUsingBlock() { (index, stop) in
if let file = self.outline.itemAtRow(index) as? ASFileItem {
selection.append(file)
}
}
return selection
}
2014-12-01 02:34:53 +00:00
// MARK: Outline View Delegate
func outlineViewSelectionDidChange(notification: NSNotification) {
2015-01-12 00:53:35 +00:00
willChangeValueForKey("hasSelection")
if outline.numberOfSelectedRows < 2 {
2015-02-14 16:43:20 +00:00
selectNode(outline.itemAtRow(outline.selectedRow) as! ASFileNode?)
2015-01-12 00:53:35 +00:00
}
didChangeValueForKey("hasSelection")
2014-12-01 02:34:53 +00:00
}
func outlineViewItemDidExpand(notification: NSNotification) {
2015-02-14 16:43:20 +00:00
let group = notification.userInfo!["NSObject"] as! ASFileGroup
group.expanded = true
updateChangeCount(.ChangeDone)
}
func outlineViewItemDidCollapse(notification: NSNotification) {
2015-02-14 16:43:20 +00:00
let group = notification.userInfo!["NSObject"] as! ASFileGroup
group.expanded = false
updateChangeCount(.ChangeDone)
}
2014-12-01 02:34:53 +00:00
func outlineView(outlineView: NSOutlineView, willDisplayCell cell: AnyObject, forTableColumn tableColumn: NSTableColumn?, item: AnyObject) {
2015-01-11 01:53:50 +00:00
if let textCell = cell as? NSTextFieldCell {
textCell.textColor = NSColor.blackColor()
if item === files.root || item === files.buildLog || item === files.uploadLog || item === files.disassembly {
textCell.font = NSFont.boldSystemFontOfSize(13.0)
} else {
textCell.font = NSFont.systemFontOfSize(13.0)
2015-02-14 16:43:20 +00:00
if !(item as! ASFileNode).exists() {
2015-01-11 01:53:50 +00:00
textCell.textColor = NSColor.redColor()
}
}
2014-12-01 02:34:53 +00:00
}
}
2015-01-12 00:53:35 +00:00
// MARK: File manipulation
@IBAction func delete(AnyObject) {
let selection = selectedFiles()
var name : String
var ref : String
if selection.count == 1 {
name = "file “\(selection[0].url.lastPathComponent)"
ref = "reference to it"
} else {
name = "\(selection.count) selected files"
ref = "references to them"
}
let alert = NSAlert()
alert.messageText =
"Do you want to move the \(name) to the Trash, or only remove the \(ref)?"
alert.addButtonWithTitle("Move to Trash")
alert.addButtonWithTitle(selection.count == 1 ? "Remove Reference" : "Remove References")
alert.addButtonWithTitle("Cancel")
2015-02-14 16:43:20 +00:00
(alert.buttons[0] as! NSButton).keyEquivalent = ""
(alert.buttons[1] as! NSButton).keyEquivalent = "\r"
2015-01-12 00:53:35 +00:00
alert.beginSheetModalForWindow(outline.window!) { (response) in
if response != NSAlertThirdButtonReturn {
if response == NSAlertFirstButtonReturn {
NSWorkspace.sharedWorkspace().recycleURLs(selection.map {$0.url}, completionHandler:nil)
}
self.files.apply { (node) in
if let group = node as? ASFileGroup {
for file in selection {
for (groupIdx, groupItem) in enumerate(group.children) {
if file as ASFileNode === groupItem {
group.children.removeAtIndex(groupIdx)
break
}
}
}
}
}
self.outline.deselectAll(self)
self.outline.reloadData()
self.updateChangeCount(.ChangeDone)
}
}
}
@IBAction func add(AnyObject) {
let panel = NSOpenPanel()
panel.canChooseFiles = true
panel.canChooseDirectories = false
panel.allowsMultipleSelection = true
panel.allowedFileTypes = ["h", "hpp", "hh", "c", "cxx", "c++", "cpp", "cc", "ino", "s", "md"]
panel.delegate = self
panel.beginSheetModalForWindow(outline.window!, completionHandler: { (returnCode: Int) -> Void in
if returnCode == NSFileHandlingPanelOKButton {
2015-02-14 16:43:20 +00:00
for url in panel.URLs as! [NSURL] {
2015-01-12 00:53:35 +00:00
self.files.addFileURL(url)
}
self.outline.deselectAll(self)
self.outline.reloadData()
self.updateChangeCount(.ChangeDone)
}
})
}
2015-02-14 16:43:20 +00:00
func panel(panel:AnyObject, shouldEnableURL url:NSURL) -> Bool {
2015-01-12 00:53:35 +00:00
var shouldEnable = true
var resourceID : AnyObject?
url.getResourceValue(&resourceID, forKey:NSURLFileResourceIdentifierKey, error:nil)
files.apply {(node) in
if let file = node as? ASFileItem {
var thisID : AnyObject?
file.url.getResourceValue(&thisID, forKey:NSURLFileResourceIdentifierKey, error:nil)
if thisID != nil && resourceID!.isEqual(thisID!) {
shouldEnable = false
}
}
}
return shouldEnable
}
var hasSelection : Bool {
return selectedFiles().count > 0
}
2015-01-12 03:24:29 +00:00
func createFileAtURL(url:NSURL) {
let type = ASFileType.guessForURL(url)
var firstPfx = ""
var prefix = ""
var lastPfx = ""
switch type {
case .Header, .CFile:
firstPfx = "/*"
prefix = " *"
lastPfx = " */"
case .CppFile, .Arduino:
prefix = "//"
case .AsmFile:
prefix = ";"
case .Markdown:
firstPfx = "<!---"
prefix = " "
lastPfx = " -->"
default:
break
}
var header = ""
2015-02-14 16:43:20 +00:00
if prefix != ("" as String) {
2015-01-12 03:24:29 +00:00
if firstPfx == "" {
firstPfx = prefix
}
if lastPfx == "" {
lastPfx = prefix
}
let dateFmt = NSDateFormatter()
dateFmt.dateFormat = "yyyy-MM-dd"
header = firstPfx + "\n" +
prefix + " Project: " + fileURL!.URLByDeletingLastPathComponent!.lastPathComponent! + "\n" +
prefix + " File: " + url.lastPathComponent! + "\n" +
2015-01-12 03:24:29 +00:00
prefix + " Created: " + dateFmt.stringFromDate(NSDate()) + "\n" +
lastPfx + "\n\n"
}
header.writeToURL(url, atomically: true, encoding: NSUTF8StringEncoding, error: nil)
files.addFileURL(url)
outline.reloadData()
}
2015-01-12 04:46:26 +00:00
@IBAction func createFile(AnyObject) {
let savePanel = NSSavePanel()
savePanel.allowedFileTypes =
[kUTTypeCSource, kUTTypeCHeader, kUTTypeCPlusPlusSource, kUTTypeCSource,
"public.assembly-source", "net.daringfireball.markdown"]
savePanel.beginSheetModalForWindow(outline.window!, completionHandler: { (returnCode) -> Void in
if returnCode == NSFileHandlingPanelOKButton {
self.createFileAtURL(savePanel.URL!)
}
})
}
// MARK: Editor configuration
2014-11-17 04:53:33 +00:00
@IBAction func changeTheme(item: NSMenuItem) {
currentTheme = UInt(item.tag)
editor.setTheme(currentTheme)
NSUserDefaults.standardUserDefaults().setObject(
ACEThemeNames.humanNameForTheme(currentTheme), forKey: kThemeKey)
updateChangeCount(.ChangeDone)
}
@IBAction func changeKeyboardHandler(item: NSMenuItem) {
keyboardHandler = ACEKeyboardHandler(rawValue: UInt(item.tag))!
NSUserDefaults.standardUserDefaults().setObject(
ACEKeyboardHandlerNames.humanNameForKeyboardHandler(keyboardHandler), forKey: kBindingsKey)
NSNotificationCenter.defaultCenter().postNotificationName(kBindingsKey, object: item)
}
override func validateUserInterfaceItem(anItem: NSValidatedUserInterfaceItem) -> Bool {
if let menuItem = anItem as? NSMenuItem {
2014-11-17 04:53:33 +00:00
if menuItem.action == "changeTheme:" {
menuItem.state = (menuItem.tag == Int(currentTheme) ? NSOnState : NSOffState)
return true
} else if menuItem.action == "changeKeyboardHandler:" {
menuItem.state = (menuItem.tag == Int(keyboardHandler.rawValue) ? NSOnState : NSOffState)
2014-12-31 09:03:30 +00:00
return true
} else if menuItem.action == "serialConnect:" {
menuItem.title = port
return true
}
}
return super.validateUserInterfaceItem(anItem)
}
@IBAction func makeTextLarger(AnyObject) {
fontSize += 1
editor.setFontSize(fontSize)
updateChangeCount(.ChangeDone)
}
@IBAction func makeTextSmaller(AnyObject) {
if fontSize > 6 {
fontSize -= 1
editor.setFontSize(fontSize)
updateChangeCount(.ChangeDone)
}
2014-11-15 03:39:10 +00:00
}
2014-11-24 13:49:47 +00:00
// MARK: Build / Upload
@IBAction func buildProject(AnyObject) {
2014-12-09 05:13:45 +00:00
selectNodeInOutline(files.buildLog)
2014-11-28 13:18:53 +00:00
builder.buildProject(board, files: files)
2014-11-24 13:49:47 +00:00
}
2014-12-01 03:26:55 +00:00
@IBAction func cleanProject(AnyObject) {
builder.cleanProject()
2014-12-09 05:13:45 +00:00
selectNodeInOutline(files.buildLog)
2014-12-01 03:26:55 +00:00
}
2014-12-07 05:20:57 +00:00
2014-12-09 05:54:30 +00:00
func rebuildPortMenu() {
willChangeValueForKey("hasValidPort")
portTool.removeAllItems()
portTool.addItemWithTitle("Title")
portTool.addItemsWithTitles(ASSerial.ports())
2014-12-09 05:54:30 +00:00
portTool.setTitle(port)
didChangeValueForKey("hasValidPort")
}
2014-12-07 05:20:57 +00:00
func menuNeedsUpdate(menu: NSMenu) {
switch menu.title {
case "Boards":
ASHardware.instance().buildBoardsMenu(menu, recentBoards: recentBoards,
target: self, selector: "selectBoard:")
boardTool.setTitle(selectedBoard)
case "Programmers":
ASHardware.instance().buildProgrammersMenu(menu, recentProgrammers: recentProgrammers,
target: self, selector: "selectProgrammer:")
progTool.setTitle(selectedProgrammer)
default:
break
}
}
2014-12-07 05:20:57 +00:00
var selectedBoard : String {
get {
let boardProps = ASHardware.instance().boards[board]
return boardProps?["name"] ?? ""
}
set (newBoard) {
for (ident, prop) in ASHardware.instance().boards {
if prop["name"] == newBoard {
2014-12-10 02:51:26 +00:00
board = ident
2014-12-07 05:20:57 +00:00
pushToFront(&recentBoards, board)
let userDefaults = NSUserDefaults.standardUserDefaults()
2015-02-14 16:43:20 +00:00
var globalBoards = userDefaults.objectForKey(kRecentBoardsKey) as! [String]
2014-12-07 05:20:57 +00:00
pushToFront(&globalBoards, board)
userDefaults.setObject(globalBoards, forKey: kRecentBoardsKey)
2014-12-07 05:20:57 +00:00
updateChangeCount(.ChangeDone)
menuNeedsUpdate(boardTool.menu!)
break
}
}
2014-12-03 14:38:13 +00:00
}
}
2014-12-07 05:20:57 +00:00
@IBAction func selectBoard(item: AnyObject) {
2015-02-14 16:43:20 +00:00
selectedBoard = (item as! NSMenuItem).title
2014-12-07 05:20:57 +00:00
}
var selectedProgrammer : String {
get {
let progProps = ASHardware.instance().programmers[programmer]
return progProps?["name"] ?? ""
}
set (newProg) {
for (ident, prop) in ASHardware.instance().programmers {
if prop["name"] == newProg {
2014-12-10 02:51:26 +00:00
programmer = ident
2014-12-07 05:20:57 +00:00
pushToFront(&recentProgrammers, programmer)
let userDefaults = NSUserDefaults.standardUserDefaults()
2015-02-14 16:43:20 +00:00
var globalProgs = userDefaults.objectForKey(kRecentProgrammersKey) as! [String]
2014-12-07 05:20:57 +00:00
pushToFront(&globalProgs, programmer)
userDefaults.setObject(globalProgs, forKey: kRecentProgrammersKey)
updateChangeCount(.ChangeDone)
progTool.setTitle(newProg)
menuNeedsUpdate(progTool.menu!)
break
}
}
2014-12-03 14:38:13 +00:00
}
}
2014-12-07 05:20:57 +00:00
@IBAction func selectProgrammer(item: AnyObject) {
2015-02-14 16:43:20 +00:00
selectedProgrammer = (item as! NSMenuItem).title
2014-12-07 05:20:57 +00:00
}
@IBAction func selectPort(item: AnyObject) {
2015-02-14 16:43:20 +00:00
port = (item as! NSPopUpButton).titleOfSelectedItem!
2014-12-07 05:20:57 +00:00
portTool.setTitle(port)
}
var hasUploadProtocol : Bool {
get {
if let proto = ASHardware.instance().boards[board]?["upload.protocol"] {
2015-02-14 16:43:20 +00:00
return proto != ("" as String)
} else {
return false
}
}
}
class func keyPathsForValuesAffectingHasUploadProtocol() -> NSSet {
return NSSet(object: "board")
}
2014-12-09 05:54:30 +00:00
var hasValidPort : Bool {
get {
2015-02-14 16:43:20 +00:00
return contains(ASSerial.ports() as! [String], port)
2014-12-09 05:54:30 +00:00
}
}
2014-12-10 02:51:26 +00:00
class func keyPathsForValuesAffectingHasValidPort() -> NSSet {
return NSSet(object: "port")
}
2014-12-09 05:54:30 +00:00
var canUpload : Bool {
get {
2015-02-14 16:43:20 +00:00
return hasValidPort && (hasUploadProtocol || programmer != ("" as String))
}
}
class func keyPathsForValuesAffectingCanUpload() -> NSSet {
2014-12-09 05:54:30 +00:00
return NSSet(objects: "hasValidPort", "hasUploadProtocol", "programmer")
}
2014-12-08 04:35:58 +00:00
@IBAction func uploadProject(sender: AnyObject) {
builder.continuation = {
2014-12-09 05:13:45 +00:00
self.selectNodeInOutline(self.files.uploadLog)
2015-01-02 06:26:10 +00:00
dispatch_async(dispatch_get_main_queue(), {
self.builder.uploadProject(self.board, programmer:self.programmer, port:self.port)
2015-01-02 06:26:10 +00:00
})
2014-12-08 04:35:58 +00:00
}
buildProject(sender)
2014-12-08 02:59:47 +00:00
}
@IBAction func uploadTerminal(sender: AnyObject) {
2015-01-07 09:30:28 +00:00
builder.uploadProject(board, programmer:programmer, port:port, mode:.Interactive)
}
@IBAction func burnBootloader(sender: AnyObject) {
self.selectNodeInOutline(self.files.uploadLog)
builder.uploadProject(board, programmer:programmer, port:port, mode:.BurnBootloader)
}
2014-12-10 14:30:51 +00:00
@IBAction func disassembleProject(sender: AnyObject) {
builder.continuation = {
self.selectNodeInOutline(self.files.disassembly)
self.builder.disassembleProject(self.board)
}
buildProject(sender)
}
2014-12-29 06:35:07 +00:00
@IBAction func serialConnect(sender: AnyObject) {
ASSerialWin.showWindowWithPort(port)
}
2014-11-15 03:39:10 +00:00
}