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
|
|
|
|
|
2014-11-17 04:39:39 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
|
|
|
class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate {
|
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?
|
2014-11-17 04:39:39 +00:00
|
|
|
var currentTheme : UInt = 0
|
|
|
|
var fontSize : UInt = 12
|
|
|
|
var themeObserver : AnyObject?
|
2014-12-09 05:54:30 +00:00
|
|
|
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]()
|
2014-12-01 02:34:53 +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 04:39:39 +00:00
|
|
|
|
2014-11-17 01:29:55 +00:00
|
|
|
// MARK: Initialization / Finalization
|
|
|
|
|
2014-11-15 03:39:10 +00:00
|
|
|
override init() {
|
|
|
|
super.init()
|
2014-11-17 04:39:39 +00:00
|
|
|
let userDefaults = NSUserDefaults.standardUserDefaults()
|
|
|
|
if let themeName = userDefaults.stringForKey(kThemeKey) {
|
|
|
|
for (themeIdx, theme) in enumerate(ACEThemeNames.themeNames() as [NSString]) {
|
|
|
|
if themeName == theme {
|
|
|
|
currentTheme = UInt(themeIdx)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let handlerName = userDefaults.stringForKey(kBindingsKey) {
|
|
|
|
for (handlerIdx, handler) in enumerate(ACEKeyboardHandlerNames.humanKeyboardHandlerNames() as [NSString]) {
|
|
|
|
if handlerName == handler {
|
|
|
|
keyboardHandler = ACEKeyboardHandler(rawValue: UInt(handlerIdx))!
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-12-09 05:54:30 +00:00
|
|
|
|
2014-11-17 04:39:39 +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)!
|
|
|
|
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
|
|
|
}
|
2014-11-16 20:10:04 +00:00
|
|
|
override func finalize() {
|
|
|
|
saveCurEditor()
|
2014-11-17 04:39:39 +00:00
|
|
|
NSNotificationCenter.defaultCenter().removeObserver(themeObserver!)
|
2014-12-09 05:54:30 +00:00
|
|
|
NSNotificationCenter.defaultCenter().removeObserver(serialObserver!)
|
2014-11-16 20:10:04 +00:00
|
|
|
}
|
|
|
|
|
2014-11-15 03:39:10 +00:00
|
|
|
override func windowControllerDidLoadNib(aController: NSWindowController) {
|
|
|
|
super.windowControllerDidLoadNib(aController)
|
2014-11-17 04:39:39 +00:00
|
|
|
editor.setShowPrintMargin(false)
|
|
|
|
editor.setTheme(currentTheme)
|
|
|
|
editor.setKeyboardHandler(keyboardHandler)
|
|
|
|
editor.setFontSize(fontSize)
|
2014-11-16 18:39:32 +00:00
|
|
|
outline.setDataSource(files)
|
2014-11-16 20:10:04 +00:00
|
|
|
files.apply() { node in
|
|
|
|
if let group = node as? ASFileGroup {
|
|
|
|
if group.expanded {
|
|
|
|
self.outline.expandItem(node)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-11-17 04:39:39 +00:00
|
|
|
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()
|
2014-12-08 03:42:45 +00:00
|
|
|
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? {
|
2014-11-17 04:39:39 +00:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2014-11-16 18:39:32 +00:00
|
|
|
func importProject(url: NSURL, error outError: NSErrorPointer) -> Bool {
|
|
|
|
let existingProject = url.URLByAppendingPathComponent(url.lastPathComponent+".avrsackproj")
|
|
|
|
if existingProject.checkResourceIsReachableAndReturnError(nil) {
|
|
|
|
fileURL = existingProject
|
|
|
|
return readFromURL(existingProject, ofType:"Project", error:outError)
|
|
|
|
}
|
|
|
|
let filesInProject =
|
|
|
|
NSFileManager.defaultManager().contentsOfDirectoryAtURL(url, includingPropertiesForKeys: nil,
|
|
|
|
options: .SkipsHiddenFiles, error: nil)!
|
|
|
|
for file in filesInProject {
|
|
|
|
files.addFileURL(file as NSURL)
|
|
|
|
}
|
|
|
|
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 {
|
|
|
|
files.setProjectURL(fileURL!)
|
2014-11-28 13:18:53 +00:00
|
|
|
builder.setProjectURL(fileURL!)
|
2014-11-17 01:29:55 +00:00
|
|
|
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 20:10:04 +00:00
|
|
|
}
|
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 {
|
|
|
|
if typeName != "Project" {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
files.setProjectURL(fileURL!)
|
2014-11-28 13:18:53 +00:00
|
|
|
builder.setProjectURL(fileURL!)
|
2014-11-17 01:29:55 +00:00
|
|
|
let projectData : NSDictionary = NSPropertyListSerialization.propertyListFromData(data, mutabilityOption: .Immutable, format: nil, errorDescription: nil) as NSDictionary
|
|
|
|
let projectVersion = projectData[kVersionKey] as Double
|
|
|
|
assert(projectVersion <= floor(kCurVersion+1.0), "Project version too new for this app")
|
2014-11-17 04:39:39 +00:00
|
|
|
if let themeName = projectData[kThemeKey] as? NSString {
|
|
|
|
for (themeIdx, theme) in enumerate(ACEThemeNames.themeNames() as [NSString]) {
|
|
|
|
if themeName == theme {
|
|
|
|
currentTheme = UInt(themeIdx)
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if let fontSz = projectData[kFontSizeKey] as? Int {
|
|
|
|
fontSize = UInt(fontSz)
|
|
|
|
}
|
2014-11-17 01:29:55 +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
|
2014-11-17 04:39:39 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
|
|
|
if (modified as NSDate).compare(logModified) == .OrderedDescending || (size as Int) != logSize {
|
|
|
|
var enc : UInt = 0
|
|
|
|
let newText = NSString(contentsOfURL:url!, usedEncoding:&enc, error:nil)
|
|
|
|
editor.setString(newText)
|
|
|
|
editor.gotoLine(1000000000, column: 0, animated: true)
|
|
|
|
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
|
|
|
|
editor.setString(NSString(contentsOfURL:file.url, usedEncoding:&enc, error:nil))
|
|
|
|
editor.setMode(UInt(file.type.aceMode))
|
2014-11-17 04:39:39 +00:00
|
|
|
editor.alphaValue = 1.0
|
2014-12-01 02:34:53 +00:00
|
|
|
mainEditor = selection
|
|
|
|
} else if let log = (selection as? ASLogNode) {
|
|
|
|
editor.setString("")
|
|
|
|
editor.setMode(UInt(ACEModeASCIIDoc))
|
|
|
|
editor.alphaValue = 0.8
|
|
|
|
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)
|
2014-11-17 04:39:39 +00:00
|
|
|
} 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)
|
|
|
|
}
|
2014-12-01 02:34:53 +00:00
|
|
|
|
|
|
|
// MARK: Outline View Delegate
|
|
|
|
|
|
|
|
func outlineViewSelectionDidChange(notification: NSNotification) {
|
|
|
|
selectNode(outline.itemAtRow(outline.selectedRow) as ASFileNode?)
|
|
|
|
}
|
2014-11-16 20:10:04 +00:00
|
|
|
func outlineViewItemDidExpand(notification: NSNotification) {
|
|
|
|
let group = notification.userInfo!["NSObject"] as ASFileGroup
|
|
|
|
group.expanded = true
|
2014-11-17 04:39:39 +00:00
|
|
|
updateChangeCount(.ChangeDone)
|
2014-11-16 20:10:04 +00:00
|
|
|
}
|
|
|
|
func outlineViewItemDidCollapse(notification: NSNotification) {
|
|
|
|
let group = notification.userInfo!["NSObject"] as ASFileGroup
|
|
|
|
group.expanded = false
|
2014-11-17 04:39:39 +00:00
|
|
|
updateChangeCount(.ChangeDone)
|
|
|
|
}
|
2014-12-01 02:34:53 +00:00
|
|
|
func outlineView(outlineView: NSOutlineView, willDisplayCell cell: AnyObject, forTableColumn tableColumn: NSTableColumn?, item: AnyObject) {
|
|
|
|
if item === files.root || item === files.buildLog || item === files.uploadLog {
|
|
|
|
(cell as NSCell).font = NSFont.boldSystemFontOfSize(13.0)
|
|
|
|
} else {
|
|
|
|
(cell as NSCell).font = NSFont.systemFontOfSize(13.0)
|
|
|
|
}
|
|
|
|
}
|
2014-11-17 04:39:39 +00:00
|
|
|
|
|
|
|
// MARK: Editor configuration
|
|
|
|
|
2014-11-17 04:53:33 +00:00
|
|
|
@IBAction func changeTheme(item: NSMenuItem) {
|
2014-11-17 04:39:39 +00:00
|
|
|
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:" {
|
2014-11-17 04:39:39 +00:00
|
|
|
menuItem.state = (menuItem.tag == Int(currentTheme) ? NSOnState : NSOffState)
|
|
|
|
return true
|
|
|
|
} else if menuItem.action == "changeKeyboardHandler:" {
|
|
|
|
menuItem.state = (menuItem.tag == Int(keyboardHandler.rawValue) ? NSOnState : NSOffState)
|
|
|
|
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.instance().ports())
|
|
|
|
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-02 12:57:18 +00:00
|
|
|
}
|
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()
|
|
|
|
var globalBoards = userDefaults.objectForKey(kRecentBoardsKey) as [String]
|
|
|
|
pushToFront(&globalBoards, board)
|
|
|
|
userDefaults.setObject(globalBoards, forKey: kRecentBoardsKey)
|
2014-12-02 12:57:18 +00:00
|
|
|
|
2014-12-07 05:20:57 +00:00
|
|
|
updateChangeCount(.ChangeDone)
|
|
|
|
menuNeedsUpdate(boardTool.menu!)
|
|
|
|
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2014-12-03 14:38:13 +00:00
|
|
|
}
|
2014-12-02 12:57:18 +00:00
|
|
|
}
|
|
|
|
|
2014-12-07 05:20:57 +00:00
|
|
|
@IBAction func selectBoard(item: AnyObject) {
|
|
|
|
selectedBoard = (item as NSMenuItem).title
|
|
|
|
}
|
|
|
|
|
|
|
|
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()
|
|
|
|
var globalProgs = userDefaults.objectForKey(kRecentProgrammersKey) as [String]
|
|
|
|
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-02 12:57:18 +00:00
|
|
|
}
|
|
|
|
|
2014-12-07 05:20:57 +00:00
|
|
|
@IBAction func selectProgrammer(item: AnyObject) {
|
|
|
|
selectedProgrammer = (item as NSMenuItem).title
|
|
|
|
}
|
|
|
|
|
|
|
|
@IBAction func selectPort(item: AnyObject) {
|
|
|
|
port = (item as NSPopUpButton).titleOfSelectedItem!
|
|
|
|
portTool.setTitle(port)
|
|
|
|
}
|
2014-12-08 01:41:19 +00:00
|
|
|
|
|
|
|
var hasUploadProtocol : Bool {
|
|
|
|
get {
|
2014-12-08 03:42:45 +00:00
|
|
|
if let proto = ASHardware.instance().boards[board]?["upload.protocol"] {
|
|
|
|
return proto != ""
|
|
|
|
} else {
|
|
|
|
return false
|
|
|
|
}
|
2014-12-08 01:41:19 +00:00
|
|
|
}
|
|
|
|
}
|
2014-12-08 03:42:45 +00:00
|
|
|
class func keyPathsForValuesAffectingHasUploadProtocol() -> NSSet {
|
|
|
|
return NSSet(object: "board")
|
|
|
|
}
|
|
|
|
|
2014-12-09 05:54:30 +00:00
|
|
|
var hasValidPort : Bool {
|
|
|
|
get {
|
|
|
|
return (ASSerial.instance().ports() as NSArray).containsObject(port)
|
|
|
|
}
|
|
|
|
}
|
2014-12-10 02:51:26 +00:00
|
|
|
class func keyPathsForValuesAffectingHasValidPort() -> NSSet {
|
|
|
|
return NSSet(object: "port")
|
|
|
|
}
|
2014-12-09 05:54:30 +00:00
|
|
|
|
2014-12-08 03:42:45 +00:00
|
|
|
var canUpload : Bool {
|
|
|
|
get {
|
2014-12-09 05:54:30 +00:00
|
|
|
return hasValidPort && (hasUploadProtocol || programmer != "")
|
2014-12-08 03:42:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
class func keyPathsForValuesAffectingCanUpload() -> NSSet {
|
2014-12-09 05:54:30 +00:00
|
|
|
return NSSet(objects: "hasValidPort", "hasUploadProtocol", "programmer")
|
2014-12-08 03:42:45 +00:00
|
|
|
}
|
|
|
|
|
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)
|
2014-12-08 04:35:58 +00:00
|
|
|
self.builder.uploadProject(self.board, programmer:self.programmer, port:self.port)
|
|
|
|
}
|
|
|
|
buildProject(sender)
|
2014-12-08 02:59:47 +00:00
|
|
|
}
|
2014-11-15 03:39:10 +00:00
|
|
|
}
|
|
|
|
|