diff options
author | Matti Tahvonen <matti.tahvonen@itmill.com> | 2007-09-27 08:43:27 +0000 |
---|---|---|
committer | Matti Tahvonen <matti.tahvonen@itmill.com> | 2007-09-27 08:43:27 +0000 |
commit | 749b99fd463276848ecbbfbbe68c850f9e313beb (patch) | |
tree | ca15633fc899b3f286f79aae367e2ff9a9377cb2 /src/com/itmill/toolkit/ui/Upload.java | |
parent | 71515370dd600b8ead68e7d76edc809c3f5f0fc2 (diff) | |
download | vaadin-framework-749b99fd463276848ecbbfbbe68c850f9e313beb.tar.gz vaadin-framework-749b99fd463276848ecbbfbbe68c850f9e313beb.zip |
Streaming upload and client side implementation for upload + progressindicator
svn changeset:2381/svn branch:trunk
Diffstat (limited to 'src/com/itmill/toolkit/ui/Upload.java')
-rw-r--r-- | src/com/itmill/toolkit/ui/Upload.java | 263 |
1 files changed, 239 insertions, 24 deletions
diff --git a/src/com/itmill/toolkit/ui/Upload.java b/src/com/itmill/toolkit/ui/Upload.java index 68276eab7a..ffa23f3e2b 100644 --- a/src/com/itmill/toolkit/ui/Upload.java +++ b/src/com/itmill/toolkit/ui/Upload.java @@ -71,6 +71,18 @@ public class Upload extends AbstractComponent implements Component.Focusable { private long focusableId = -1; + private boolean isUploading; + + private long contentLength = -1; + + private int totalBytes; + + /** + * ProgressListener to which information about progress is sent during + * upload + */ + private ProgressListener progressListener; + /* TODO: Add a default constructor, receive to temp file. */ /** @@ -95,25 +107,16 @@ public class Upload extends AbstractComponent implements Component.Focusable { return "upload"; } - /** - * Invoked when the value of a variable has changed. - * - * @see com.itmill.toolkit.ui.AbstractComponent#changeVariables(java.lang.Object, - * java.util.Map) - */ - public void changeVariables(Object source, Map variables) { - - // Checks the variable name - if (!variables.containsKey("stream")) - return; - - // Gets the upload stream - UploadStream upload = (UploadStream) variables.get("stream"); + public void receiveUpload(UploadStream upload) { + if (!isUploading) + throw new IllegalStateException("uploading not started"); // Gets file properties String filename = upload.getContentName(); String type = upload.getContentType(); + fireStarted(filename, type); + // Gets the output target stream OutputStream out = receiver.receiveUpload(filename, type); if (out == null) @@ -121,33 +124,54 @@ public class Upload extends AbstractComponent implements Component.Focusable { "Error getting outputstream from upload receiver"); InputStream in = upload.getStream(); + if (null == in) { // No file, for instance non-existent filename in html upload fireUploadInterrupted(filename, type, 0); + endUpload(); return; } + byte buffer[] = new byte[BUFFER_SIZE]; int bytesRead = 0; - long totalBytes = 0; + totalBytes = 0; try { while ((bytesRead = in.read(buffer)) > 0) { out.write(buffer, 0, bytesRead); totalBytes += bytesRead; + if (progressListener != null && contentLength > 0) { + // update progress if listener set and contentLength + // received + progressListener.updateProgress(totalBytes, contentLength); + } } - // Download successfull + // upload successful out.close(); fireUploadSuccess(filename, type, totalBytes); + endUpload(); requestRepaint(); } catch (IOException e) { // Download interrupted fireUploadInterrupted(filename, type, totalBytes); + endUpload(); } } /** + * Invoked when the value of a variable has changed. + * + * @see com.itmill.toolkit.ui.AbstractComponent#changeVariables(java.lang.Object, + * java.util.Map) + */ + public void changeVariables(Object source, Map variables) { + // NOP + + } + + /** * Paints the content of this component. * * @param target @@ -164,6 +188,10 @@ public class Upload extends AbstractComponent implements Component.Focusable { if (this.tabIndex >= 0) target.addAttribute("tabindex", this.tabIndex); + target.addAttribute("state", isUploading); + + target.addVariable(this, "fake", true); + target.addUploadStreamVariable(this, "stream"); } @@ -198,12 +226,16 @@ public class Upload extends AbstractComponent implements Component.Focusable { private static final Method UPLOAD_SUCCEEDED_METHOD; + private static final Method UPLOAD_STARTED_METHOD; + static { try { UPLOAD_FINISHED_METHOD = FinishedListener.class.getDeclaredMethod( "uploadFinished", new Class[] { FinishedEvent.class }); UPLOAD_FAILED_METHOD = FailedListener.class.getDeclaredMethod( "uploadFailed", new Class[] { FailedEvent.class }); + UPLOAD_STARTED_METHOD = StartedListener.class.getDeclaredMethod( + "uploadStarted", new Class[] { StartedEvent.class }); UPLOAD_SUCCEEDED_METHOD = SucceededListener.class .getDeclaredMethod("uploadSucceeded", new Class[] { SucceededEvent.class }); @@ -282,21 +314,21 @@ public class Upload extends AbstractComponent implements Component.Focusable { } /** - * Gets the length of the file. + * Gets the MIME Type of the file. * - * @return the length. + * @return the MIME type. */ - public long getLength() { - return length; + public String getMIMEType() { + return type; } /** - * Gets the MIME Type of the file. + * Gets the length of the file. * - * @return the MIME type. + * @return the length. */ - public String getMIMEType() { - return type; + public long getLength() { + return length; } } @@ -361,6 +393,85 @@ public class Upload extends AbstractComponent implements Component.Focusable { } /** + * Upload.Started event is sent when the upload is started to received. + * + * @author IT Mill Ltd. + * @version + * @VERSION@ + * @since 5.0 + */ + public class StartedEvent extends Component.Event { + + /** + * Serial generated by eclipse. + */ + private static final long serialVersionUID = -3984393770487403525L; + private String filename; + private String type; + + /** + * + * @param source + * @param filename + * @param MIMEType + * @param length + */ + public StartedEvent(Upload source, String filename, String MIMEType) { + super(source); + this.filename = filename; + this.type = MIMEType; + } + + /** + * Uploads where the event occurred. + * + * @return the Source of the event. + */ + public Upload getUpload() { + return (Upload) getSource(); + } + + /** + * Gets the file name. + * + * @return the filename. + */ + public String getFilename() { + return filename; + } + + /** + * Gets the MIME Type of the file. + * + * @return the MIME type. + */ + public String getMIMEType() { + return type; + } + + + } + + /** + * Receives the events when the upload starts. + * + * @author IT Mill Ltd. + * @version + * @VERSION@ + * @since 5.0 + */ + public interface StartedListener { + + /** + * Upload has started. + * + * @param event + * the Upload started event. + */ + public void uploadStarted(StartedEvent event); + } + + /** * Receives the events when the uploads are ready. * * @author IT Mill Ltd. @@ -418,6 +529,26 @@ public class Upload extends AbstractComponent implements Component.Focusable { } /** + * Adds the upload started event listener. + * + * @param listener + * the Listener to be added. + */ + public void addListener(StartedListener listener) { + addListener(StartedEvent.class, listener, UPLOAD_STARTED_METHOD); + } + + /** + * Removes the upload started event listener. + * + * @param listener + * the Listener to be removed. + */ + public void removeListener(StartedListener listener) { + removeListener(FinishedEvent.class, listener, UPLOAD_STARTED_METHOD); + } + + /** * Adds the upload received event listener. * * @param listener @@ -484,6 +615,17 @@ public class Upload extends AbstractComponent implements Component.Focusable { * @param MIMEType * @param length */ + protected void fireStarted(String filename, String MIMEType) { + fireEvent(new Upload.StartedEvent(this, filename, MIMEType)); + } + + /** + * Emit upload received event. + * + * @param filename + * @param MIMEType + * @param length + */ protected void fireUploadReceived(String filename, String MIMEType, long length) { fireEvent(new Upload.FinishedEvent(this, filename, MIMEType, length)); @@ -572,4 +714,77 @@ public class Upload extends AbstractComponent implements Component.Focusable { return this.focusableId; } + /** + * Sets the size of the file currently being uploaded. + * + * @param contentLength + */ + public void setUploadSize(long contentLength) { + this.contentLength = contentLength; + } + + /** + * Go into upload state. This is to prevent double uploading on same + * component. + */ + public void startUpload() { + if (isUploading) + throw new IllegalStateException("uploading already started"); + isUploading = true; + } + + /** + * Go into state where new uploading can begin. + */ + public void endUpload() { + isUploading = false; + contentLength = -1; + } + + public boolean isUploading() { + return isUploading; + } + + /** + * Gets read bytes of the file currently being uploaded. + * + * @return bytes + */ + public long getBytesRead() { + return totalBytes; + } + + /** + * Returns size of file currently being uploaded. Value sane only during + * upload. + * + * @return size in bytes + */ + public long getUploadSize() { + return contentLength; + } + + /** + * Sets listener to track progress of upload. + * + * @param progressListener + */ + public void setProgressListener(ProgressListener progressListener) { + this.progressListener = progressListener; + } + + /** + * ProgressListener receives events to track progress of upload. + */ + public interface ProgressListener { + /** + * Updates progress to listener + * + * @param readBytes + * bytes transferred + * @param contentLength + * total size of file currently being uploaded, -1 if unknown + */ + public void updateProgress(long readBytes, long contentLength); + } } |