Skip to content

Commit

Permalink
Merge branch 'release/v0.0.1-Pre-Alpha9'
Browse files Browse the repository at this point in the history
  • Loading branch information
ronaldmannak committed Mar 12, 2019
2 parents 4bfb2d4 + e484303 commit d7997b1
Show file tree
Hide file tree
Showing 170 changed files with 15,254 additions and 1,878 deletions.
4 changes: 2 additions & 2 deletions App/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Cocoa
@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {

private lazy var preferencesWindowController = NSWindowController.instantiate(storyboard: "Preferences")
private lazy var preferencesWindowController = NSWindowController.instantiate(storyboard: "PreferencesWindow")
private lazy var toolchainWindowController = NSWindowController.instantiate(storyboard: "InstallToolchain")
private lazy var templateWindowController = NSWindowController.instantiate(storyboard: "Template")

Expand Down Expand Up @@ -54,7 +54,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {

func applicationDidFinishLaunching(_ aNotification: Notification) {

if UserDefaults.standard.bool(forKey: UserDefaultStrings.doNotShowDependencyWizard.rawValue) == false {
if UserDefaults.standard[.showInstallToolchainOnStartup] == true {
showInstallToolchains(self)
} else {
(DocumentController.shared as! DocumentController).newProject(self)
Expand Down
260 changes: 205 additions & 55 deletions Composite.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions Documents/DocumentController+Action.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,13 +69,63 @@ extension DocumentController {
// DocumentWindow.tabbingPreference = nil
}


@IBAction func newWindowForTab(_ sender: Any?) {

guard let document = currentDocument else { return }

document.makeWindowControllers()
guard let newTab = document.windowControllers.last?.window else { return }
document.windowControllers.first?.window?.addTabbedWindow(newTab, ordered: .below)
}

@IBAction func newProject(_ sender: Any?) {

guard let delegate = NSApplication.shared.delegate as? AppDelegate else { return }
delegate.showProjectTemplates(self)
}

@IBAction func newFile(_ sender: Any?) {

guard let currentDocument = self.currentDocument, let currentDirectory = currentDocument.fileURL?.deletingLastPathComponent(), let window = currentDocument.windowControllers.first?.window else { return }

let savePanel = NSSavePanel()
savePanel.directoryURL = currentDirectory
savePanel.isExtensionHidden = false
savePanel.allowedFileTypes = ["scilla", "sol", "js", "json"] // TODO: default extension should be first item
savePanel.beginSheetModal(for: window) { (result) in

guard result == .OK, let location = savePanel.url else { return }
print("success: \(location)")

// Create empty document
let document = TextDocument()

document.save(to: location, ofType: "", for: .saveOperation, completionHandler: { error in

guard error == nil else {
let alert = NSAlert(error: error!)
alert.runModal()
return
}

savePanel.close()

if let currentDocument = currentDocument as? TextDocument {
document.project = currentDocument.project
} else if let currentDocument = currentDocument as? ProjectDocument {
document.project = currentDocument
}
assert(document.project != nil)
self.replace(document, inController: currentDocument.windowControllers.first!)


// if let windowController = currentDocument.windowControllers.first! as? ProjectWindowController {
// windowController.document = document
// }
})

}
}

}
159 changes: 139 additions & 20 deletions Documents/DocumentController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,16 @@

import Cocoa

protocol AdditionalDocumentPreparing: AnyObject {

func didMakeDocumentForExisitingFile(url: URL)
}

class DocumentController: NSDocumentController {

private(set) lazy var autosaveDirectoryURL: URL = try! FileManager.default.url(for: .autosavedInformationDirectory, in: .userDomainMask, appropriateFor: nil, create: true)

private(set) var accessorySelectedEncoding: String.Encoding?

// MARK: -
// MARK: Lifecycle
Expand Down Expand Up @@ -53,14 +59,17 @@ class DocumentController: NSDocumentController {

if let textDocument = document as? TextDocument {

// 1. If displayDocument is false, user selected text document in the
// 1. invalidate encoding that was set in the open panel
self.accessorySelectedEncoding = nil

// 2. If displayDocument is false, user selected text document in the
// file navigator. Caller will handle displaying the document.
guard displayDocument == true else {
completionHandler(textDocument, documentWasAlreadyOpen, error)
return
}

// 2. Show text document in a new window.
// 3. Show text document in a new window.
self.show(textDocument: textDocument, url: url) { document, error in
completionHandler(document, documentWasAlreadyOpen, error)
}
Expand All @@ -86,19 +95,6 @@ class DocumentController: NSDocumentController {
}
}

override func beginOpenPanel(_ openPanel: NSOpenPanel, forTypes inTypes: [String]?, completionHandler: @escaping (Int) -> Void) {

// TODO: If inTypes is passed to super, the open dialog will allow *every*
// document to be opened, including PDFs and PNGs
// Quick fix: hardcoding supported contracts.
// This doesn't affect opening other files (e.g. js or json) from within
// project window's file navigator.
// inTypes?.compactMap { print($0) }
super.beginOpenPanel(openPanel, forTypes: ["composite", "scilla", "sol"]) { (result: Int) in
completionHandler(result)
}
}

/// open untitled document
/// Not supported
override func openUntitledDocumentAndDisplay(_ displayDocument: Bool) throws -> NSDocument {
Expand All @@ -109,12 +105,38 @@ class DocumentController: NSDocumentController {
/// instantiates a document located by a URL, of a specified type, and returns it if successful
override func makeDocument(withContentsOf url: URL, ofType typeName: String) throws -> NSDocument {

// [caution] This method may be called from a background thread due to concurrent-opening.

do {
try self.checkOpeningSafetyOfDocument(at: url, typeName: typeName)

} catch {
// ask user for opening file
try DispatchQueue.syncOnMain {
guard self.presentError(error) else { throw CocoaError(.userCancelled) }
}
}

// make document
let document = try super.makeDocument(withContentsOf: url, ofType: typeName)

(document as? AdditionalDocumentPreparing)?.didMakeDocumentForExisitingFile(url: url)

return document
}

override func beginOpenPanel(_ openPanel: NSOpenPanel, forTypes inTypes: [String]?, completionHandler: @escaping (Int) -> Void) {

// TODO: If inTypes is passed to super, the open dialog will allow *every*
// document to be opened, including PDFs and PNGs
// Quick fix: hardcoding supported contracts.
// This doesn't affect opening other files (e.g. js or json) from within
// project window's file navigator.
// inTypes?.compactMap { print($0) }
super.beginOpenPanel(openPanel, forTypes: ["composite", "scilla", "sol"]) { (result: Int) in
completionHandler(result)
}
}

/// add encoding menu to open panel
/*override func beginOpenPanel(_ openPanel: NSOpenPanel, forTypes inTypes: [String]?, completionHandler: @escaping (Int) -> Void) {
Expand All @@ -139,13 +161,26 @@ class DocumentController: NSDocumentController {
}
}*/


override func noteNewRecentDocument(_ document: NSDocument) {

// Only add ProjectDocuments to the recent open menu, not individual text documents
guard document is ProjectDocument else { return }
super.noteNewRecentDocument(document)
}


/// return enability of actions
override func validateUserInterfaceItem(_ item: NSValidatedUserInterfaceItem) -> Bool {

if item.action == #selector(newWindowForTab) {
return self.currentDocument != nil
}

if item.action == #selector(newFile(_:)) {
return self.currentDocument != nil
}

return super.validateUserInterfaceItem(item)
}

Expand All @@ -154,14 +189,37 @@ class DocumentController: NSDocumentController {
// Show new file template here
}

@IBAction func newWindowForTab(_ sender: Any?) {
/// Check file before creating a new document instance.
///
/// - Parameters:
/// - url: The location of the new document object.
/// - typeName: The type of the document.
/// - Throws: `DocumentReadError`
private func checkOpeningSafetyOfDocument(at url: URL, typeName: String) throws {

guard let document = currentDocument else { return }
// check if the file is possible binary
let cfTypeName = typeName as CFString
let binaryTypes = [kUTTypeImage,
kUTTypeAudiovisualContent,
kUTTypeGNUZipArchive,
kUTTypeZipArchive,
kUTTypeBzip2Archive]
if binaryTypes.contains(where: { UTTypeConformsTo(cfTypeName, $0) }),
!UTTypeEqual(cfTypeName, kUTTypeScalableVectorGraphics) // SVG is plain-text (except SVGZ)
{
throw DocumentReadError(kind: .binaryFile(type: typeName), url: url)
}

document.makeWindowControllers()
guard let newTab = document.windowControllers.last?.window else { return }
document.windowControllers.first?.window?.addTabbedWindow(newTab, ordered: .below)
// check if the file is enorm large
let fileSizeThreshold = UserDefaults.standard[.largeFileAlertThreshold]
if fileSizeThreshold > 0,
let fileSize = (try? url.resourceValues(forKeys: [.fileSizeKey]))?.fileSize,
fileSize > fileSizeThreshold
{
throw DocumentReadError(kind: .tooLarge(size: fileSize), url: url)
}
}


/// Based on TextEdit example, see https://stackoverflow.com/questions/34497218/nsdocument-opening-over-a-default-document
func replace(_ document: NSDocument, inController controller: NSWindowController) {
Expand All @@ -170,6 +228,11 @@ class DocumentController: NSDocumentController {

let documentToBeReplaced = currentDocument // Note: Can be nil

// Pass project
if let document = document as? TextDocument, document.project == nil, let documentToBeReplaced = documentToBeReplaced as? TextDocument {
document.project = documentToBeReplaced.project
}

document.addWindowController(controller) //(controller.copy() as! NSWindowController)
controller.document = document

Expand Down Expand Up @@ -295,3 +358,59 @@ extension DocumentController {
textDocument.showWindows()
}
}


// MARK: - Error

private struct DocumentReadError: LocalizedError, RecoverableError {

enum ErrorKind {
case binaryFile(type: String)
case tooLarge(size: Int)
}

let kind: ErrorKind
let url: URL


var errorDescription: String? {

switch self.kind {
case .binaryFile:
return String(format: "The file “%@” doesn’t appear to be text data.".localized,
self.url.lastPathComponent)

case .tooLarge(let size):
return String(format: "The file “%@” has a size of %@.".localized,
self.url.lastPathComponent,
ByteCountFormatter.string(fromByteCount: Int64(size), countStyle: .file))
}
}


var recoverySuggestion: String? {

switch self.kind {
case .binaryFile(let type):
let localizedTypeName = (UTTypeCopyDescription(type as CFString)?.takeRetainedValue() as String?) ?? "unknown file type"
return String(format: "The file is %@.\n\nDo you really want to open the file?".localized, localizedTypeName)

case .tooLarge:
return "Opening such a large file can make the application slow or unresponsive.\n\nDo you really want to open the file?".localized
}
}


var recoveryOptions: [String] {

return ["Open".localized,
"Cancel".localized]
}


func attemptRecovery(optionIndex recoveryOptionIndex: Int) -> Bool {

return (recoveryOptionIndex == 0)
}

}
Loading

0 comments on commit d7997b1

Please sign in to comment.