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;
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();
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;
}
public final native VHtml5File getFile(int fileIndex)
/*-{
- return this.dataTransfer.files[i];
+ return this.dataTransfer.files[fileIndex];
}-*/;
}
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)
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)
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;
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;
*/
protected void doHandleFileUpload(Request request, Response response)
throws IOException, FileUploadException {
+
// Create a new file upload handler
final FileUpload upload = createFileUpload();
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() {
};
- // 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) {
*/
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;
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)
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);
+ }
+ }
}
/**
}
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
* 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 {
/**
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
}
+
}
}
package com.vaadin.tests.dd;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import com.vaadin.event.dd.acceptCriteria.IsSameSourceAndTarget;
import com.vaadin.event.dd.acceptCriteria.Not;
import com.vaadin.terminal.Resource;
+import com.vaadin.terminal.StreamResource;
import com.vaadin.terminal.ThemeResource;
+import com.vaadin.terminal.StreamResource.StreamSource;
import com.vaadin.terminal.gwt.client.MouseEventDetails;
import com.vaadin.tests.components.TestBase;
import com.vaadin.tests.util.TestUtils;
import com.vaadin.ui.Label;
import com.vaadin.ui.SplitPanel;
import com.vaadin.ui.Tree;
+import com.vaadin.ui.Window;
import com.vaadin.ui.AbsoluteLayout.ComponentPosition;
+import com.vaadin.ui.DragAndDropWrapper.WrapperTransferable.Html5File;
import com.vaadin.ui.Tree.TreeDragMode;
import com.vaadin.ui.Tree.TreeDropTargetDetails;
+import com.vaadin.ui.Upload.Receiver;
public class DDTest6 extends TestBase {
private SplitPanel sp;
+ private BeanItemContainer<File> fs1;
+
private static int count;
private static DDTest6 instance;
tree1 = new Tree("Volume 1");
tree1.setImmediate(true);
- BeanItemContainer<File> fs1 = new BeanItemContainer<File>(File.class);
+ fs1 = new BeanItemContainer<File>(File.class);
tree1.setContainerDataSource(fs1);
for (int i = 0; i < files.length; i++) {
fs1.addBean(files[i]);
public static class File {
private Resource icon = DOC;
private String name;
+ private ByteArrayOutputStream bas;
+ private String type;
public File(String fileName) {
name = fileName;
}
+ public File(String fileName, ByteArrayOutputStream bas) {
+ this(fileName);
+ this.bas = bas;
+ }
+
public void setIcon(Resource icon) {
this.icon = icon;
}
public String getName() {
return name;
}
+
+ public void setType(String type) {
+ this.type = type;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public Resource getResource() {
+ StreamSource streamSource = new StreamSource() {
+ public InputStream getStream() {
+ if (bas != null) {
+ byte[] byteArray = bas.toByteArray();
+ return new ByteArrayInputStream(byteArray);
+ }
+ // TODO Auto-generated method stub
+ return null;
+ }
+ };
+ return new StreamResource(streamSource, getName(), DDTest6.get());
+ }
}
public static class Folder extends File {
@Override
protected String getDescription() {
- return "dd: tree and web desktop tests. TODO add traditional icon area on right side with DragAndDropWrapper and absolutelayouts + more files, auto-opening folders";
+ return "dd: tree and web desktop tests. FF36 supports draggin files from client side. (try dragging png image + double click) TODO more files, auto-opening folders";
}
@Override
return 119;
}
+ private void openFile(File file) {
+ // ATM supports only images.
+
+ Embedded embedded = new Embedded(file.getName(), file.getResource());
+ Window w = new Window(file.getName());
+ w.addComponent(embedded);
+ getMainWindow().addWindow(w);
+
+ }
+
static class FolderView extends DragAndDropWrapper implements DropHandler {
static final HashMap<Folder, FolderView> views = new HashMap<Folder, FolderView>();
File draggedFile = (File) ((DataBoundTransferable) dropEvent
.getTransferable()).getItemId();
DDTest6.get().setParent(draggedFile, folder);
+ } else {
+ // expecting this to be an html5 drag
+ WrapperTransferable tr = (WrapperTransferable) dropEvent
+ .getTransferable();
+ Html5File[] files2 = tr.getFiles();
+ if (files2 != null) {
+ for (Html5File html5File : files2) {
+ String fileName = html5File.getFileName();
+ // int bytes = html5File.getFileSize();
+ final ByteArrayOutputStream bas = new ByteArrayOutputStream();
+
+ Receiver receiver = new Receiver() {
+ public OutputStream receiveUpload(String filename,
+ String MIMEType) {
+ return bas;
+ }
+ };
+
+ html5File.receive(receiver);
+
+ File file = new File(fileName, bas);
+ file.setType(html5File.getType());
+ DDTest6.get().fs1.addBean(file);
+ DDTest6.get().tree1.setChildrenAllowed(file, false);
+ DDTest6.get().setParent(file, folder);
+ }
+
+ }
+
}
}
l.addListener(new LayoutClickListener() {
public void layoutClick(LayoutClickEvent event) {
- if (file instanceof Folder) {
- if (event.isDoubleClick()) {
+ if (event.isDoubleClick()) {
+ if (file instanceof Folder) {
get().tree1.setValue(file);
+ } else {
+ String type = file.getType();
+ if (type != null && type.equals("image/png")) {
+ DDTest6.get().openFile(file);
+ }
}
-
}
}
f = (File) ((DataBoundTransferable) dropEvent
.getTransferable()).getItemId();
}
- // TODO accept drags from Tree too
if (f != null) {
get().setParent(f, (Folder) FileIcon.this.file);