@@ -67,6 +67,9 @@ final class OutlineViewController: NSViewController {
6767 column. title = " Cell "
6868 outlineView. addTableColumn ( column)
6969
70+ outlineView. setDraggingSourceOperationMask ( . move, forLocal: false )
71+ outlineView. registerForDraggedTypes ( [ . fileURL] )
72+
7073 self . scrollView. documentView = outlineView
7174 self . scrollView. contentView. automaticallyAdjustsContentInsets = false
7275 self . scrollView. contentView. contentInsets = . init( top: 10 , left: 0 , bottom: 0 , right: 0 )
@@ -150,6 +153,84 @@ extension OutlineViewController: NSOutlineViewDataSource {
150153 }
151154 return false
152155 }
156+
157+ /// write dragged file(s) to pasteboard
158+ func outlineView( _ outlineView: NSOutlineView , pasteboardWriterForItem item: Any ) -> NSPasteboardWriting ? {
159+ guard let fileItem = item as? Item else { return nil }
160+ return fileItem. url as NSURL
161+ }
162+
163+ /// declare valid drop target
164+ func outlineView(
165+ _ outlineView: NSOutlineView ,
166+ validateDrop info: NSDraggingInfo ,
167+ proposedItem item: Any ? ,
168+ proposedChildIndex index: Int
169+ ) -> NSDragOperation {
170+ guard let fileItem = item as? Item else { return [ ] }
171+ // -1 index indicates that we are hovering over a row in outline view (folder or file)
172+ if index == - 1 {
173+ if !fileItem. isFolder {
174+ outlineView. setDropItem ( fileItem. parent, dropChildIndex: index)
175+ }
176+ return . move
177+ }
178+ return [ ]
179+ }
180+
181+ /// handle successful or unsuccessful drop
182+ func outlineView(
183+ _ outlineView: NSOutlineView ,
184+ acceptDrop info: NSDraggingInfo ,
185+ item: Any ? ,
186+ childIndex index: Int
187+ ) -> Bool {
188+ guard let pasteboardItems = info. draggingPasteboard. readObjects ( forClasses: [ NSURL . self] ) else { return false }
189+ let fileItemURLS = pasteboardItems. compactMap { $0 as? URL }
190+
191+ guard let fileItemDestination = item as? Item else { return false }
192+ let destParentURL = fileItemDestination. url
193+
194+ for fileItemURL in fileItemURLS {
195+ let destURL = destParentURL. appendingPathComponent ( fileItemURL. lastPathComponent)
196+ // cancel dropping file item on self or in parent directory
197+ if fileItemURL == destURL || fileItemURL == destParentURL {
198+ return false
199+ }
200+
201+ // Needs to come before call to .removeItem or else race condition occurs
202+ guard let srcFileItem = try ? workspace? . workspaceClient? . getFileItem ( fileItemURL. relativePath) else {
203+ return false
204+ }
205+
206+ if WorkspaceClient . FileItem. fileManger. fileExists ( atPath: destURL. path) {
207+ let shouldReplace = replaceFileDialog ( fileName: fileItemURL. lastPathComponent)
208+ guard shouldReplace else {
209+ return false
210+ }
211+ do {
212+ try WorkspaceClient . FileItem. fileManger. removeItem ( at: destURL)
213+ } catch {
214+ fatalError ( error. localizedDescription)
215+ }
216+ }
217+
218+ self . moveFile ( file: srcFileItem, to: destURL)
219+ }
220+ return true
221+ }
222+
223+ func replaceFileDialog( fileName: String ) -> Bool {
224+ let alert = NSAlert ( )
225+ alert. messageText = """
226+ A file or folder with the name \( fileName) already exists in the destination folder. Do you want to replace it?
227+ """
228+ alert. informativeText = " This action is irreversible! "
229+ alert. alertStyle = . warning
230+ alert. addButton ( withTitle: " Replace " )
231+ alert. addButton ( withTitle: " Cancel " )
232+ return alert. runModal ( ) == . alertFirstButtonReturn
233+ }
153234}
154235
155236// MARK: - NSOutlineViewDelegate
@@ -299,8 +380,12 @@ extension OutlineViewController: NSMenuDelegate {
299380
300381extension OutlineViewController : OutlineTableViewCellDelegate {
301382 func moveFile( file: Item , to destination: URL ) {
302- workspace? . closeTab ( item: . codeEditor( file. id) )
383+ if !file. isFolder {
384+ workspace? . closeTab ( item: . codeEditor( file. id) )
385+ }
303386 file. move ( to: destination)
304- workspace? . openTab ( item: file)
387+ if !file. isFolder {
388+ workspace? . openTab ( item: file)
389+ }
305390 }
306391}
0 commit comments