Implement drag and drop of files in Project view

This commit is contained in:
Matthias Neeracher 2015-12-25 03:00:20 +01:00 committed by Matthias Neeracher
parent e5427ae2bb
commit 0ecc67146c
2 changed files with 76 additions and 2 deletions

View File

@ -54,7 +54,7 @@ private let kNodeTypeGroup = "Group"
private let kNodeTypeFile = "File" private let kNodeTypeFile = "File"
private let kNameKey = "Name" private let kNameKey = "Name"
class ASFileNode { class ASFileNode : Equatable {
var name : String var name : String
init(name: String) { init(name: String) {
@ -97,6 +97,10 @@ class ASFileNode {
} }
} }
func ==(a: ASFileNode, b: ASFileNode) -> Bool {
return a === b
}
class ASLogNode : ASFileNode { class ASLogNode : ASFileNode {
var path : String var path : String
@ -268,6 +272,7 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
var buildLog = ASLogNode(name: "Build Log", path: "build/build.log") var buildLog = ASLogNode(name: "Build Log", path: "build/build.log")
var uploadLog = ASLogNode(name: "Upload Log", path: "build/upload.log") var uploadLog = ASLogNode(name: "Upload Log", path: "build/upload.log")
var disassembly = ASLogNode(name: "Disassembly", path: "build/disasm.log") var disassembly = ASLogNode(name: "Disassembly", path: "build/disasm.log")
var dragged = [ASFileNode]()
func addFileURL(url: NSURL, omitUnknown: Bool = true) { func addFileURL(url: NSURL, omitUnknown: Bool = true) {
let type = ASFileType.guessForURL(url) let type = ASFileType.guessForURL(url)
@ -326,4 +331,67 @@ class ASFileTree : NSObject, NSOutlineViewDataSource {
func outlineView(outlineView: NSOutlineView, objectValueForTableColumn tableColumn: NSTableColumn?, byItem item: AnyObject?) -> AnyObject? { func outlineView(outlineView: NSOutlineView, objectValueForTableColumn tableColumn: NSTableColumn?, byItem item: AnyObject?) -> AnyObject? {
return (item as! ASFileNode).nodeName() return (item as! ASFileNode).nodeName()
} }
let kLocalReorderPasteboardType = "ASFilePasteboardType"
func outlineView(outlineView: NSOutlineView, writeItems items: [AnyObject], toPasteboard pasteboard: NSPasteboard) -> Bool {
dragged = items as! [ASFileNode]
pasteboard.declareTypes([kLocalReorderPasteboardType], owner: self)
pasteboard.setData(NSData(), forType: kLocalReorderPasteboardType)
return true
}
func itemIsDescendentOfDrag(outlineView: NSOutlineView, item: ASFileNode) -> Bool {
if dragged.contains(item) {
return true
} else if item is ASProject {
return false
} else {
return itemIsDescendentOfDrag(outlineView, item: outlineView.parentForItem(item) as! ASFileNode)
}
}
func outlineView(outlineView: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: AnyObject?, proposedChildIndex index: Int) -> NSDragOperation {
if info.draggingPasteboard().availableTypeFromArray([kLocalReorderPasteboardType]) == nil {
return NSDragOperation.None // Only allow reordering drags
}
for drag in dragged {
switch (drag) {
case is ASProject, is ASLogNode:
return NSDragOperation.None // Don't allow root or log nodes to be dragged
default:
break
}
}
switch (item) {
case is ASProject, is ASFileGroup:
if itemIsDescendentOfDrag(outlineView, item: item as! ASFileNode) {
return NSDragOperation.None // Don't allow drag on member of dragged items or a descendent thereof
}
default:
return NSDragOperation.None // Don't allow drag onto leaf
}
return NSDragOperation.Generic
}
func outlineView(outlineView: NSOutlineView, acceptDrop info: NSDraggingInfo, item: AnyObject?, var childIndex insertAtIndex: Int) -> Bool {
let parent : ASFileGroup = (item as? ASFileGroup) ?? root
if insertAtIndex == NSOutlineViewDropOnItemIndex {
insertAtIndex = parent.children.count
}
outlineView.beginUpdates()
for item in dragged {
let origParent = outlineView.parentForItem(item) as! ASFileGroup
let origIndex = origParent.children.indexOf(item)!
origParent.children.removeAtIndex(origIndex)
outlineView.removeItemsAtIndexes(NSIndexSet(index:origIndex), inParent:origParent, withAnimation:NSTableViewAnimationOptions.EffectNone)
if origParent == parent && insertAtIndex > origIndex {
insertAtIndex -= 1
}
parent.children.insert(item, atIndex:insertAtIndex)
outlineView.insertItemsAtIndexes(NSIndexSet(index:insertAtIndex), inParent: parent, withAnimation:NSTableViewAnimationOptions.EffectGap)
insertAtIndex += 1
}
outlineView.endUpdates()
(outlineView.delegate() as! ASProjDoc).updateChangeCount(NSDocumentChangeType.ChangeDone)
return true
}
} }

View File

@ -126,6 +126,10 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
editors.setViews([editor], inGravity: .Top) editors.setViews([editor], inGravity: .Top)
outline.registerForDraggedTypes([files.kLocalReorderPasteboardType])
outline.setDraggingSourceOperationMask(NSDragOperation.Every, forLocal: true)
outline.setDraggingSourceOperationMask(NSDragOperation.None, forLocal: false)
outline.setDataSource(files) outline.setDataSource(files)
files.apply() { node in files.apply() { node in
if let group = node as? ASFileGroup { if let group = node as? ASFileGroup {
@ -496,9 +500,11 @@ class ASProjDoc: NSDocument, NSOutlineViewDelegate, NSMenuDelegate, NSOpenSavePa
} }
} }
} }
func outlineView(outlineView: NSOutlineView, shouldTrackCell cell: NSCell, forTableColumn tableColumn: NSTableColumn?, item: AnyObject) -> Bool {
return outlineView.isRowSelected(outlineView.rowForItem(item))
}
// MARK: File manipulation // MARK: File manipulation
@IBAction func delete(_: AnyObject) { @IBAction func delete(_: AnyObject) {
let selection = selectedFiles() let selection = selectedFiles()
var name : String var name : String