summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMatti Tahvonen <matti.tahvonen@itmill.com>2010-03-12 14:57:49 +0000
committerMatti Tahvonen <matti.tahvonen@itmill.com>2010-03-12 14:57:49 +0000
commitf1d07c89844bbd3d46281eb95166f609bd4191e8 (patch)
tree744d90694ca2fe2deaddb2f50b77a008ccb9ad8d /src
parentc1fee1ce305961af5576ea434685b392adc728b1 (diff)
downloadvaadin-framework-f1d07c89844bbd3d46281eb95166f609bd4191e8.tar.gz
vaadin-framework-f1d07c89844bbd3d46281eb95166f609bd4191e8.zip
A proper (FF36 only) file drag support, enhanced test case. Should be forward compatible.
svn changeset:11835/svn branch:6.3
Diffstat (limited to 'src')
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java132
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java2
-rw-r--r--src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5File.java10
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java2
-rw-r--r--src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java75
-rw-r--r--src/com/vaadin/ui/DragAndDropWrapper.java84
6 files changed, 221 insertions, 84 deletions
diff --git a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
index 2beef216f2..606b382c26 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/VDragAndDropWrapper.java
@@ -13,6 +13,7 @@ import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.DeferredCommand;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.xhr.client.XMLHttpRequest;
import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.Paintable;
@@ -193,44 +194,16 @@ public class VDragAndDropWrapper extends VCustomComponent implements
transferable.setData("filecount", fileCount);
for (int i = 0; i < fileCount; i++) {
final int fileId = filecounter++;
- final VHtml5File file = event.getFile(fileCount);
- transferable.setData("fn" + fileId, file.getName());
- transferable.setData("ft" + fileId, file.getType());
- transferable.setData("fs" + fileId, file.getSize());
- DeferredCommand.addCommand(new Command() {
- public void execute() {
- /*
- * File contents is sent deferred to allow quick
- * reaction on GUI although file upload may last long.
- * TODO make this use apache file upload instead of our
- * variable post like in upload. Currently stalls the
- * GUI during upload. Also need to use dataurl to
- * support all possible bytes in file content
- */
- file.readAsDataUrl(new Callback() {
- public void handleFile(JavaScriptObject object) {
- client.updateVariable(client
- .getPid(VDragAndDropWrapper.this),
- "file" + fileId, object.toString(),
- true);
-
- }
- });
-
- }
- });
+ final VHtml5File file = event.getFile(i);
+ transferable.setData("fi" + i, "" + fileId);
+ transferable.setData("fn" + i, file.getName());
+ transferable.setData("ft" + i, file.getType());
+ transferable.setData("fs" + i, file.getSize());
+ postFile(fileId, file);
}
}
- // TODO remove this when above cleaner and more standard compliance
- // system works
- String fileAsString = event.getFileAsString(0);
- if (fileAsString != null) {
- ApplicationConnection.getConsole().log(fileAsString);
- transferable.setData("fileContents", fileAsString);
- }
-
VDragAndDropManager.get().endDrag();
vaadinDragEvent = null;
event.preventDefault();
@@ -239,6 +212,97 @@ public class VDragAndDropWrapper extends VCustomComponent implements
return false;
}
+ static class ExtendedXHR extends XMLHttpRequest {
+
+ protected ExtendedXHR() {
+ }
+
+ public final native void sendBinary(JavaScriptObject data)
+ /*-{
+ //this.overrideMimeType('text/plain; charset=x-user-defined-binary');
+ this.sendAsBinary(data);
+ }-*/;
+
+ }
+
+ /**
+ *
+ * Currently supports only FF36 as no other browser supprots natively File
+ * api.
+ *
+ * @param fileId
+ * @param data
+ */
+ private void postFile(final int fileId, final VHtml5File file) {
+ DeferredCommand.addCommand(new Command() {
+ public void execute() {
+ /*
+ * File contents is sent deferred to allow quick reaction on GUI
+ * although file upload may last long. TODO make this use apache
+ * file upload instead of our variable post like in upload.
+ * Currently stalls the GUI during upload. Also need to use
+ * dataurl to support all possible bytes in file content
+ */
+ file.readAsBinary(new Callback() {
+ public void handleFile(final JavaScriptObject object) {
+
+ DeferredCommand.addCommand(new Command() {
+
+ public void execute() {
+
+ ExtendedXHR extendedXHR = (ExtendedXHR) ExtendedXHR
+ .create();
+ extendedXHR.open("POST", client.getAppUri());
+ extendedXHR
+ .setRequestHeader(
+ "PaintableId",
+ client
+ .getPid(VDragAndDropWrapper.this));
+ extendedXHR.setRequestHeader("FileId", ""
+ + fileId);
+
+ // extendedXHR.setRequestHeader("Connection",
+ // "close");
+
+ multipartSend(
+ extendedXHR,
+ object,
+ "XHRFILE"
+ + client
+ .getPid(VDragAndDropWrapper.this)
+ + "." + fileId);
+
+ }
+ });
+ }
+ });
+
+ }
+ });
+
+ }
+
+ private native void multipartSend(JavaScriptObject xhr,
+ JavaScriptObject data, String name)
+ /*-{
+
+ var boundaryString = "------------------------------------------VAADINXHRFILEUPLOAD";
+ var boundary = "--" + boundaryString;
+ var CRLF = "\r\n";
+ xhr.setRequestHeader("Content-type", "multipart/form-data; boundary=\"" + boundaryString + "\"");
+ var requestBody = boundary
+ + CRLF
+ + "Content-Disposition: form-data; name=\""+name+"\"; filename=\"file\""
+ + CRLF
+ + "Content-Type: application/octet-stream" // hard coded, type sent separately
+ + CRLF + CRLF + data.target.result + CRLF + boundary + "--" + CRLF;
+ xhr.setRequestHeader("Content-Length", requestBody.length);
+
+
+ xhr.sendAsBinary(requestBody);
+
+ }-*/;
+
public VDropHandler getDropHandler() {
return dropHandler;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java
index 9d5bafc2b7..47b1ba81ed 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5DragEvent.java
@@ -59,7 +59,7 @@ public class VHtml5DragEvent extends NativeEvent {
public final native VHtml5File getFile(int fileIndex)
/*-{
- return this.dataTransfer.files[i];
+ return this.dataTransfer.files[fileIndex];
}-*/;
}
diff --git a/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5File.java b/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5File.java
index ead0ee6ceb..1a1db2910d 100644
--- a/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5File.java
+++ b/src/com/vaadin/terminal/gwt/client/ui/dd/VHtml5File.java
@@ -14,17 +14,17 @@ public class VHtml5File extends JavaScriptObject {
public native final String getName()
/*-{
- return name;
+ return this.name;
}-*/;
public native final String getType()
/*-{
- return type;
+ return this.type;
}-*/;
public native final int getSize()
/*-{
- return size;
+ return this.size;
}-*/;
public native final void readAsBinary(final Callback callback)
@@ -33,7 +33,9 @@ public class VHtml5File extends JavaScriptObject {
r.onloadend = function(content) {
callback.@com.vaadin.terminal.gwt.client.ui.dd.VHtml5File.Callback::handleFile(Lcom/google/gwt/core/client/JavaScriptObject;)(content);
};
- r.readAsBinary(this);
+ r.readAsBinaryString(this);
+ var j = 0;
+
}-*/;
public native final void readAsDataUrl(final Callback callback)
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
index d1b8ec7671..d3243fab73 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractApplicationServlet.java
@@ -1252,6 +1252,8 @@ public abstract class AbstractApplicationServlet extends HttpServlet implements
return RequestType.STATIC_FILE;
} else if (isApplicationRequest(request)) {
return RequestType.APPLICATION_RESOURCE;
+ } else if (request.getHeader("FileId") != null) {
+ return RequestType.FILE_UPLOAD;
}
return RequestType.OTHER;
diff --git a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
index 481e42c0e9..ada3869269 100644
--- a/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
+++ b/src/com/vaadin/terminal/gwt/server/AbstractCommunicationManager.java
@@ -62,6 +62,7 @@ import com.vaadin.terminal.gwt.client.ApplicationConnection;
import com.vaadin.terminal.gwt.server.ComponentSizeValidator.InvalidLayout;
import com.vaadin.ui.AbstractField;
import com.vaadin.ui.Component;
+import com.vaadin.ui.DragAndDropWrapper;
import com.vaadin.ui.Upload;
import com.vaadin.ui.Window;
import com.vaadin.ui.Upload.UploadException;
@@ -359,6 +360,7 @@ public abstract class AbstractCommunicationManager implements
*/
protected void doHandleFileUpload(Request request, Response response)
throws IOException, FileUploadException {
+
// Create a new file upload handler
final FileUpload upload = createFileUpload();
@@ -386,22 +388,6 @@ public abstract class AbstractCommunicationManager implements
if (item.isFormField()) {
// ignored, upload requests contains only files
} else {
- int separatorPos = name.lastIndexOf("_");
- final String pid = name.substring(0, separatorPos);
- final Upload uploadComponent = (Upload) idPaintableMap
- .get(pid);
- if (uploadComponent == null) {
- throw new FileUploadException(
- "Upload component not found");
- }
- if (uploadComponent.isReadOnly()) {
- throw new FileUploadException(
- "Warning: ignored file upload because upload component is set as read-only");
- }
- synchronized (application) {
- // put upload component into receiving state
- uploadComponent.startUpload();
- }
final UploadStream upstream = new UploadStream() {
public String getContentName() {
@@ -422,22 +408,55 @@ public abstract class AbstractCommunicationManager implements
};
- // tell UploadProgressListener which component is receiving
- // file
- pl.setUpload(uploadComponent);
+ if (name.startsWith("XHRFILE")) {
+ String[] split = item.getFieldName().substring(7)
+ .split("\\.");
+ DragAndDropWrapper ddw = (DragAndDropWrapper) idPaintableMap
+ .get(split[0]);
+
+ ddw.receiveFile(upstream, split[1]);
- try {
- uploadComponent.receiveUpload(upstream);
- } catch (UploadException e) {
- // error happened while receiving file. Handle the
- // error in the same manner as it would have happened in
- // variable change.
+ String debugId = ddw.getDebugId();
+
+ } else {
+
+ int separatorPos = name.lastIndexOf("_");
+ final String pid = name.substring(0, separatorPos);
+ final Upload uploadComponent = (Upload) idPaintableMap
+ .get(pid);
+ if (uploadComponent == null) {
+ throw new FileUploadException(
+ "Upload component not found");
+ }
+ if (uploadComponent.isReadOnly()) {
+ throw new FileUploadException(
+ "Warning: ignored file upload because upload component is set as read-only");
+ }
synchronized (application) {
- handleChangeVariablesError(application,
- uploadComponent, e,
- new HashMap<String, Object>());
+ // put upload component into receiving state
+ uploadComponent.startUpload();
+ }
+
+ // tell UploadProgressListener which component is
+ // receiving
+ // file
+ pl.setUpload(uploadComponent);
+
+ try {
+ uploadComponent.receiveUpload(upstream);
+ } catch (UploadException e) {
+ // error happened while receiving file. Handle the
+ // error in the same manner as it would have
+ // happened in
+ // variable change.
+ synchronized (application) {
+ handleChangeVariablesError(application,
+ uploadComponent, e,
+ new HashMap<String, Object>());
+ }
}
}
+
}
}
} catch (final FileUploadException e) {
diff --git a/src/com/vaadin/ui/DragAndDropWrapper.java b/src/com/vaadin/ui/DragAndDropWrapper.java
index 3274b60b47..a848d7af40 100644
--- a/src/com/vaadin/ui/DragAndDropWrapper.java
+++ b/src/com/vaadin/ui/DragAndDropWrapper.java
@@ -3,8 +3,11 @@
*/
package com.vaadin.ui;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.HashMap;
import java.util.Map;
-import java.util.Set;
import com.vaadin.event.Transferable;
import com.vaadin.event.TransferableImpl;
@@ -15,10 +18,13 @@ import com.vaadin.event.dd.DropTargetDetails;
import com.vaadin.event.dd.DropTargetDetailsImpl;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.UploadStream;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.terminal.gwt.client.ui.VDragAndDropWrapper;
import com.vaadin.terminal.gwt.client.ui.dd.HorizontalDropLocation;
import com.vaadin.terminal.gwt.client.ui.dd.VerticalDropLocation;
+import com.vaadin.terminal.gwt.server.AbstractApplicationServlet;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable.Html5File;
import com.vaadin.ui.Upload.Receiver;
@ClientWidget(VDragAndDropWrapper.class)
@@ -27,9 +33,24 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget,
public class WrapperTransferable extends TransferableImpl {
+ private Html5File[] files;
+
public WrapperTransferable(Component sourceComponent,
Map<String, Object> rawVariables) {
super(sourceComponent, rawVariables);
+ Integer fc = (Integer) rawVariables.get("filecount");
+ if (fc != null) {
+ files = new Html5File[fc];
+ for (int i = 0; i < fc; i++) {
+ Html5File file = new Html5File();
+ String id = (String) rawVariables.get("fi" + i);
+ file.name = (String) rawVariables.get("fn" + i);
+ file.size = (Integer) rawVariables.get("fs" + i);
+ file.type = (String) rawVariables.get("ft" + i);
+ files[i] = file;
+ receivers.put(id, file);
+ }
+ }
}
/**
@@ -51,21 +72,28 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget,
}
public Html5File[] getFiles() {
- // TODO Auto-generated method stub
- return null;
+ return files;
}
public class Html5File {
+ public String name;
+ private String id;
+ private int size;
+ private Receiver receiver;
+ private String type;
+
public String getFileName() {
- // TODO Auto-generated method stub
- return null;
+ return name;
+ }
+
+ public int getFileSize() {
+ return size;
}
- // public int getFileSize() {
- // // TODO Auto-generated method stub
- // return 0;
- // }
+ public String getType() {
+ return type;
+ }
/**
* HTML5 drags are read from client disk with a callback. This and
@@ -77,14 +105,15 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget,
* implementation writes the file contents as it arrives.
*/
public void receive(Receiver receiver) {
- // TODO Auto-generated method stub
-
+ this.receiver = receiver;
}
}
}
+ private Map<String, Html5File> receivers = new HashMap<String, Html5File>();
+
public class WrapperDropDetails extends DropTargetDetailsImpl {
/**
@@ -195,13 +224,34 @@ public class DragAndDropWrapper extends CustomComponent implements DropTarget,
return dragStartMode;
}
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
- super.changeVariables(source, variables);
+ /**
+ * This method should only be used by Vaadin terminal implementation. This
+ * is not end user api.
+ *
+ * TODO should fire progress events + end/succes events like upload
+ *
+ * @param upstream
+ * @param fileId
+ */
+ public void receiveFile(UploadStream upstream, String fileId) {
+ Html5File file = receivers.get(fileId);
+ if (file != null && file.receiver != null) {
+ OutputStream receiveUpload = file.receiver.receiveUpload(file
+ .getFileName(), "TODO");
+
+ InputStream stream = upstream.getStream();
+ byte[] buf = new byte[AbstractApplicationServlet.MAX_BUFFER_SIZE];
+ int bytesRead;
+ try {
+ while ((bytesRead = stream.read(buf)) != -1) {
+ receiveUpload.write(buf, 0, bytesRead);
+ }
+ } catch (IOException e) {
+ // TODO Auto-generated catch block
+ e.printStackTrace();
+ }
- Set<String> keySet = variables.keySet();
- for (String string : keySet) {
- // TODO get files
}
+
}
}