Skip to content
This repository has been archived by the owner on Apr 24, 2021. It is now read-only.

Improved drag&drop behavior #1269

Merged
merged 3 commits into from
Mar 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions ide/app/lib/ui/files_controller.dart
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,23 @@ class FilesController implements TreeViewDelegate {
}
}

String treeViewDropCellsEffect(TreeView view,
List<String> nodesUIDs,
String nodeUID) {
if (nodeUID == null) {
return "none";
}
if (_isDifferentProject(nodesUIDs, nodeUID)) {
return "copy";
} else {
if (_isValidMove(nodesUIDs, nodeUID)) {
return "move";
} else {
return "none";
}
}
}

void treeViewDrop(TreeView view, String nodeUID, html.DataTransfer dataTransfer) {
Folder destinationFolder = _filesMap[nodeUID] as Folder;
for(html.File file in dataTransfer.files) {
Expand All @@ -254,6 +271,23 @@ class FilesController implements TreeViewDelegate {
reader.readAsArrayBuffer(file);
}
}

bool _isDifferentProject(List<String> nodesUIDs, String targetNodeUID) {
if (targetNodeUID == null) {
return false;
}
Resource destination = _filesMap[targetNodeUID];
Project destinationProject = destination is Project ? destination :
destination.project;
for(String nodeUID in nodesUIDs) {
Resource node = _filesMap[nodeUID];
// Check if the resource have the same top-level container.
if (node.project == destinationProject) {
return false;
}
}
return true;
}

// Returns true if the move is valid:
// - We don't allow moving a file to its parent since it's a no-op.
Expand Down Expand Up @@ -300,16 +334,31 @@ class FilesController implements TreeViewDelegate {
void treeViewDropCells(TreeView view,
List<String> nodesUIDs,
String targetNodeUID) {
Resource destination = _filesMap[targetNodeUID];
if (_isValidMove(nodesUIDs, targetNodeUID)) {
_workspace.moveTo(nodesUIDs.map((f) => _filesMap[f]).toList(), destination);
Folder destination = _filesMap[targetNodeUID] as Folder;
if (_isDifferentProject(nodesUIDs, targetNodeUID)) {
List<Future> futures = [];
for(String nodeUID in nodesUIDs) {
Resource res = _filesMap[nodeUID];
futures.add(destination.importResource(res));
}
Future.wait(futures).catchError((e) {
_delegate.showErrorMessage('Error while importing files', e);
});
} else {
if (_isValidMove(nodesUIDs, targetNodeUID)) {
_workspace.moveTo(nodesUIDs.map((f) => _filesMap[f]).toList(), destination);
}
}
}

bool treeViewAllowsDropCells(TreeView view,
List<String> nodesUIDs,
String destinationNodeUID) {
return _isValidMove(nodesUIDs, destinationNodeUID);
if (_isDifferentProject(nodesUIDs, destinationNodeUID)) {
return true;
} else {
return _isValidMove(nodesUIDs, destinationNodeUID);
}
}

bool treeViewAllowsDrop(TreeView view,
Expand Down
5 changes: 5 additions & 0 deletions ide/app/lib/ui/files_controller_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,9 @@ abstract class FilesControllerDelegate {
* [resource].
*/
List<ContextAction> getActionsFor(List<Resource> resources);

/**
* The implementation of this method should report an error.
*/
void showErrorMessage(String title, String message);
}
7 changes: 6 additions & 1 deletion ide/app/lib/ui/widgets/treeview.dart
Original file line number Diff line number Diff line change
Expand Up @@ -339,11 +339,16 @@ class TreeView implements ListViewDelegate {
}

String listViewDropEffect(ListView view, MouseEvent event) {
List<String> dragSelection = _innerDragSelection(event.dataTransfer);
String nodeUID = null;
if (_currentDragOverCell != null) {
nodeUID = _currentDragOverCell.nodeUID;
}
return _delegate.treeViewDropEffect(this, event.dataTransfer, nodeUID);
if (dragSelection != null) {
return _delegate.treeViewDropCellsEffect(this, dragSelection, nodeUID);
} else {
return _delegate.treeViewDropEffect(this, event.dataTransfer, nodeUID);
}
}

List<String> _innerDragSelection(DataTransfer dataTransfer) {
Expand Down
11 changes: 11 additions & 0 deletions ide/app/lib/ui/widgets/treeview_delegate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,17 @@ abstract class TreeViewDelegate {
String treeViewDropEffect(TreeView view,
DataTransfer dataTransfer,
String nodeUID) => null;

/**
* This method is called when a selection of TreeView is dragged,
* on dragenter.
* Return 'copy', 'move', 'link' or 'none'.
* It will adjust the visual of the mouse cursor when the item is
* dragged over the treeview.
*/
String treeViewDropCellsEffect(TreeView view,
List<String> nodesUIDs,
String nodeUID) => null;

/**
* This method is called when the dragged item is actually dropped on the
Expand Down
28 changes: 24 additions & 4 deletions ide/app/lib/workspace.dart
Original file line number Diff line number Diff line change
Expand Up @@ -730,7 +730,11 @@ class Folder extends Container {
});
}

Future<File> importFile(chrome.ChromeFileEntry sourceEntry) {
/**
* This method will import a file entry that might be from an other
* filesystem to the current folder.
*/
Future<File> importFileEntry(chrome.ChromeFileEntry sourceEntry) {
return createNewFile(sourceEntry.name).then((File file) {
sourceEntry.readBytes().then((chrome.ArrayBuffer buffer) {
return file.setBytes(buffer.getBytes());
Expand All @@ -739,15 +743,19 @@ class Folder extends Container {
});
}

Future importFolder(chrome.DirectoryEntry entry) {
/**
* This method will copy a directory entry that might be from an other
* filesystem to the current folder.
*/
Future importDirectoryEntry(chrome.DirectoryEntry entry) {
return createNewFolder(entry.name).then((Folder folder) {
return entry.createReader().readEntries().then((List<chrome.Entry> entries) {
List<Future> futures = [];
for(chrome.Entry child in entries) {
if (child is chrome.DirectoryEntry) {
futures.add(folder.importFolder(child));
futures.add(folder.importDirectoryEntry(child));
} else if (child is chrome.ChromeFileEntry) {
futures.add(folder.importFile(child));
futures.add(folder.importFileEntry(child));
}
}
return Future.wait(futures).then((_) {
Expand All @@ -756,6 +764,18 @@ class Folder extends Container {
});
});
}

/**
* This method will copy a resource entry that might be from an other
* filesystem to the current folder.
*/
Future importResource(Resource res) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a copy from a different part of the workspace? Perhaps add some dartdoc to that effect?

Also, we way want to rename some methods to clarify the types that they take. importResource operates on a workspace resource; importFile and importFolder both operate on DOM filesystem entries. Perhaps change the 2nd two methods to importFileEntry and importDirectoryEntry for clarity?

if (res.entry is chrome.ChromeFileEntry) {
return importFileEntry(res.entry);
} else if (res.entry is chrome.DirectoryEntry) {
return importDirectoryEntry(res.entry);
}
}

Future delete() {
return _dirEntry.removeRecursively().then((_) => _parent._removeChild(this));
Expand Down
10 changes: 4 additions & 6 deletions ide/app/spark.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2498,8 +2498,7 @@ class GitAuthenticationDialog extends SparkActionWithDialog {
}

class ImportFileAction extends SparkAction implements ContextAction {
ImportFileAction(Spark spark) : super(spark, "file-import", "Import File…") {
}
ImportFileAction(Spark spark) : super(spark, "file-import", "Import File…");

void _invoke([List<ws.Resource> resources]) {
chrome.ChooseEntryOptions options = new chrome.ChooseEntryOptions(
Expand All @@ -2508,7 +2507,7 @@ class ImportFileAction extends SparkAction implements ContextAction {
chrome.ChromeFileEntry entry = res.entry;
if (entry != null) {
ws.Folder folder = resources.first;
folder.importFile(entry).catchError((e) {
folder.importFileEntry(entry).catchError((e) {
spark.showErrorMessage('Error while importing file', e);
});
}
Expand All @@ -2521,8 +2520,7 @@ class ImportFileAction extends SparkAction implements ContextAction {
}

class ImportFolderAction extends SparkAction implements ContextAction {
ImportFolderAction(Spark spark) : super(spark, "folder-import", "Import Folder…") {
}
ImportFolderAction(Spark spark) : super(spark, "folder-import", "Import Folder…");

void _invoke([List<ws.Resource> resources]) {
chrome.ChooseEntryOptions options = new chrome.ChooseEntryOptions(
Expand All @@ -2531,7 +2529,7 @@ class ImportFolderAction extends SparkAction implements ContextAction {
chrome.DirectoryEntry entry = res.entry;
if (entry != null) {
ws.Folder folder = resources.first;
folder.importFolder(entry).catchError((e) {
folder.importDirectoryEntry(entry).catchError((e) {
spark.showErrorMessage('Error while importing folder', e);
});
}
Expand Down