return re.test(uri);
}-*/;
- private native String getAppUri()/*-{
+ public native String getAppUri()/*-{
return $wnd.itmtk.appUri;
}-*/;
import com.itmill.toolkit.terminal.gwt.client.ui.IPanel;
import com.itmill.toolkit.terminal.gwt.client.ui.IPasswordField;
import com.itmill.toolkit.terminal.gwt.client.ui.IPopupCalendar;
+import com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator;
import com.itmill.toolkit.terminal.gwt.client.ui.IScrollTable;
import com.itmill.toolkit.terminal.gwt.client.ui.ISelect;
import com.itmill.toolkit.terminal.gwt.client.ui.ISlider;
} else if ("com.itmill.toolkit.terminal.gwt.client.ui.IFilterSelect"
.equals(className)) {
return new IFilterSelect();
+ } else if ("com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator"
+ .equals(className)) {
+ return new IProgressIndicator();
}
+
return new IUnknownComponent();
/*
return "com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelHorizontal";
} else if ("vsplitpanel".equals(tag)) {
return "com.itmill.toolkit.terminal.gwt.client.ui.ISplitPanelVertical";
+ } else if ("progressindicator".equals(tag)) {
+ return "com.itmill.toolkit.terminal.gwt.client.ui.IProgressIndicator";
}
return "com.itmill.toolkit.terminal.gwt.client.ui.IUnknownComponent";
--- /dev/null
+package com.itmill.toolkit.terminal.gwt.client.ui;
+
+import com.google.gwt.user.client.DOM;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Timer;
+import com.google.gwt.user.client.ui.Widget;
+import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
+import com.itmill.toolkit.terminal.gwt.client.Paintable;
+import com.itmill.toolkit.terminal.gwt.client.UIDL;
+
+public class IProgressIndicator extends Widget implements Paintable {
+
+ private static final String CLASSNAME = "i-progressindicator";
+ Element wrapper = DOM.createDiv();
+ Element indicator = DOM.createDiv();
+ private ApplicationConnection client;
+ private Poller poller;
+
+ public IProgressIndicator() {
+ setElement(wrapper);
+ setStyleName(CLASSNAME);
+ DOM.appendChild(wrapper, indicator);
+ poller = new Poller();
+ }
+
+ public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
+ poller.cancel();
+ this.client = client;
+ if(client.updateComponent(this, uidl, true))
+ return;
+ boolean indeterminate = uidl.getBooleanAttribute("indeterminate");
+
+ if(indeterminate) {
+ // TODO put up some image or something
+ } else {
+ try {
+ float f = Float.parseFloat(uidl.getStringAttribute("state"));
+ int size = Math.round(100*f);
+ DOM.setStyleAttribute(indicator, "width", size + "%");
+ } catch (Exception e) {
+ }
+ }
+ poller.scheduleRepeating(uidl.getIntAttribute("pollinginterval"));
+ }
+
+ class Poller extends Timer {
+
+ public void run() {
+ client.sendPendingVariableChanges();
+ }
+
+ }
+
+}
package com.itmill.toolkit.terminal.gwt.client.ui;
+import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormSubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormSubmitEvent;
-import com.google.gwt.user.client.ui.Frame;
-import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.Widget;
import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
import com.itmill.toolkit.terminal.gwt.client.Paintable;
import com.itmill.toolkit.terminal.gwt.client.UIDL;
-public class IUpload extends FormPanel implements Paintable, ClickListener {
-
+public class IUpload extends FormPanel implements Paintable, ClickListener,
+ FormHandler {
+
+ /**
+ * FileUpload component that opens native OS dialog to select file.
+ */
FileUpload fu = new FileUpload();
-
+
Panel panel = new FlowPanel();
-
+
ApplicationConnection client;
private String paintableId;
+ /**
+ * Button that initiates uploading
+ */
private Button b;
-
+
+ /**
+ * When expecting big files, programmer may initiate some UI changes when
+ * uploading the file starts. Bit after submitting file we'll visit the
+ * server to check possible changes.
+ */
+ private Timer t;
+
+ /**
+ * some browsers tries to send form twice if submit is called in button
+ * click handler, some don't submit at all without it, so we need to track
+ * if form is already being submitted
+ */
+ private boolean submitted = false;
+
public IUpload() {
super();
setEncoding(FormPanel.ENCODING_MULTIPART);
- setMethod(FormPanel.METHOD_POST);
+ setMethod(FormPanel.METHOD_POST);
+
setWidget(panel);
- panel.add(new Label("UPLOAD component incomplete"));
panel.add(fu);
- b = new Button("Upload");
+ // TODO
+ b = new Button("Click to Upload");
b.addClickListener(this);
panel.add(b);
-
- addFormHandler(new FormHandler() {
- public void onSubmitComplete(FormSubmitCompleteEvent event) {
- if(client != null) {
- // request update
- client.sendPendingVariableChanges();
- }
- }
-
- public void onSubmit(FormSubmitEvent event) {
- if (fu.getFilename().length() == 0) {
- event.setCancelled(true);
- }
- }
- });
+
+ addFormHandler(this);
}
public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
this.client = client;
this.paintableId = uidl.getId();
- if(uidl.hasAttribute("caption"))
+ setAction(client.getAppUri());
+
+ if (uidl.hasAttribute("caption"))
b.setText(uidl.getStringAttribute("caption"));
+ fu.setName(paintableId + "_file");
}
this.submit();
}
+ public void onSubmit(FormSubmitEvent event) {
+ if (fu.getFilename().length() == 0 || submitted) {
+ event.setCancelled(true);
+ ApplicationConnection.getConsole().log(
+ "Submit cancelled (no file or already submitted)");
+ return;
+ }
+ submitted = true;
+ ApplicationConnection.getConsole().log("Submitted form");
+
+ disableUpload();
+
+ /*
+ * visit server after upload to see possible changes from UploadStarted
+ * event
+ */
+ t = new Timer() {
+ public void run() {
+ client.sendPendingVariableChanges();
+ }
+ };
+ t.schedule(800);
+ }
+
+ protected void disableUpload() {
+ b.setEnabled(false);
+ fu.setVisible(false);
+ }
+ protected void enableUploaod() {
+ b.setEnabled(true);
+ fu.setVisible(true);
+ }
+
+ public void onSubmitComplete(FormSubmitCompleteEvent event) {
+ if (client != null) {
+ if (t != null)
+ t.cancel();
+ ApplicationConnection.getConsole().log("Submit complete");
+ client.sendPendingVariableChanges();
+ }
+ submitted = false;
+ enableUploaod();
+ }
+
}
--- /dev/null
+.i-progressindicator {
+ background: red;
+ height: 20px;
+}
+.i-progressindicator div {
+ background: green;
+ height:100%;
+}
\ No newline at end of file
@import "tree/tree.css";\r
@import "splitpanel/splitpanel.css";\r
@import "select/filterselect.css";\r
+@import "progressindicator/progressindicator.css";
\r
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.xml.sax.SAXException;
import com.itmill.toolkit.Application;
Application application = null;
try {
+ // handle file upload if multipart request
+ if(ServletFileUpload.isMultipartContent(request)) {
+ application = getApplication(request);
+ getApplicationManager(application).handleFileUpload(request, response);
+ return;
+ }
+
// Update browser details
WebBrowser browser = WebApplicationContext.getApplicationContext(
request.getSession()).getBrowser();
// Is this a download request from application
DownloadStream download = null;
- // The rest of the process is synchronized with the application
- // in order to guarantee that no parallel variable handling is
- // made
- synchronized (application) {
-
+
// Handles AJAX UIDL requests
String resourceId = request.getPathInfo();
if (resourceId != null && resourceId.startsWith(AJAX_UIDL_URI)) {
writeAjaxPage(request, response, window, themeName);
}
- }
// For normal requests, transform the window
if (download != null)
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.fileupload.FileItemIterator;
+import org.apache.commons.fileupload.FileItemStream;
+import org.apache.commons.fileupload.FileUploadException;
+import org.apache.commons.fileupload.ProgressListener;
+import org.apache.commons.fileupload.servlet.ServletFileUpload;
+import org.apache.commons.fileupload.util.Streams;
+
import com.itmill.toolkit.Application;
import com.itmill.toolkit.Application.WindowAttachEvent;
import com.itmill.toolkit.Application.WindowDetachEvent;
import com.itmill.toolkit.terminal.DownloadStream;
import com.itmill.toolkit.terminal.Paintable;
import com.itmill.toolkit.terminal.URIHandler;
+import com.itmill.toolkit.terminal.UploadStream;
import com.itmill.toolkit.terminal.VariableOwner;
import com.itmill.toolkit.terminal.Paintable.RepaintRequestEvent;
import com.itmill.toolkit.ui.Component;
import com.itmill.toolkit.ui.FrameWindow;
+import com.itmill.toolkit.ui.Upload;
import com.itmill.toolkit.ui.Window;
/**
application.removeListener((Application.WindowDetachListener) this);
}
+ /**
+ * Handles file upload request submitted via Upload component.
+ *
+ * @param request
+ * @param response
+ * @throws IOException
+ */
+ public void handleFileUpload(HttpServletRequest request,
+ HttpServletResponse response) throws IOException {
+ // Create a new file upload handler
+ ServletFileUpload upload = new ServletFileUpload();
+
+ UploadProgressListener pl = new UploadProgressListener();
+
+ upload.setProgressListener(pl);
+
+ // Parse the request
+ FileItemIterator iter;
+
+ try {
+ iter = upload.getItemIterator(request);
+ /* ATM this loop is run only once as we are uploading one file per
+ * request.
+ */
+ while (iter.hasNext()) {
+ FileItemStream item = iter.next();
+ String name = item.getFieldName();
+ final String filename = item.getName();
+ final String mimeType = item.getContentType();
+ final InputStream stream = item.openStream();
+ if (item.isFormField()) {
+ // ignored, upload requests contian only files
+ } else {
+ String pid = name.split("_")[0];
+ Upload uploadComponent = (Upload) idPaintableMap.get(pid);
+ if (uploadComponent == null) {
+ throw new FileUploadException(
+ "Upload component not found");
+ }
+ synchronized (application) {
+ // put upload component into receiving state
+ uploadComponent.startUpload();
+ }
+ UploadStream upstream = new UploadStream() {
+
+ public String getContentName() {
+ return filename;
+ }
+
+ public String getContentType() {
+ return mimeType;
+ }
+
+ public InputStream getStream() {
+ return stream;
+ }
+
+ public String getStreamName() {
+ return "stream";
+ }
+
+ };
+
+ // tell UploadProgressListener which component is receiving file
+ pl.setUpload(uploadComponent);
+
+ uploadComponent.receiveUpload(upstream);
+ }
+ }
+ } catch (FileUploadException e) {
+ e.printStackTrace();
+ }
+
+ // Send short response to acknowledge client that request was done
+ response.setContentType("text/html");
+ OutputStream out = response.getOutputStream();
+ PrintWriter outWriter = new PrintWriter(new BufferedWriter(
+ new OutputStreamWriter(out, "UTF-8")));
+ outWriter.print("<html><body>download handled</body></html>");
+ outWriter.flush();
+ out.close();
+ }
+
public void handleUidlRequest(HttpServletRequest request,
HttpServletResponse response) throws IOException {
- // repaint requested or sesssion has timed out and new one is created
+ // repaint requested or session has timed out and new one is created
boolean repaintAll = (request.getParameter(GET_PARAM_REPAINT_ALL) != null)
|| request.getSession().isNew();
PrintWriter outWriter = new PrintWriter(new BufferedWriter(
new OutputStreamWriter(out, "UTF-8")));
- // TODO Move dirt elsewhere
- outWriter.print(")/*{"); // some dirt to prevent cross site scripting
- // vulnerabilities
-
try {
// Is this a download request from application
// Sets the response type
response.setContentType("application/json; charset=UTF-8");
+ // some dirt to prevent cross site scripting
+ outWriter.print(")/*{");
+
outWriter.print("\"changes\":[");
paintTarget = new JsonPaintTarget(this, outWriter);
// Reset sent locales
locales = null;
requireLocale(application.getLocale().toString());
-
+
} else
paintables = getDirtyComponents();
if (paintables != null) {
w.setTerminal(application.getMainWindow()
.getTerminal());
}
- /* This does not seem to happen in tk5, but remember this case:
- else if (p instanceof Component) {
- if (((Component) p).getParent() == null
- || ((Component) p).getApplication() == null) {
- // Component requested repaint, but is no
- // longer attached: skip
- paintablePainted(p);
- continue;
- }
- }
- */
+ /*
+ * This does not seem to happen in tk5, but remember
+ * this case: else if (p instanceof Component) { if
+ * (((Component) p).getParent() == null ||
+ * ((Component) p).getApplication() == null) { //
+ * Component requested repaint, but is no // longer
+ * attached: skip paintablePainted(p); continue; } }
+ */
paintTarget.startTag("change");
paintTarget.addAttribute("format", "uidl");
String pid = getPaintableId(p);
if (request.getParameter("theme") != null) {
themeName = request.getParameter("theme");
}
- if (themeName == null) themeName = "default";
-
+ if (themeName == null)
+ themeName = "default";
+
// TODO We should only precache the layouts that are not
// cached already
int resourceIndex = 0;
Map m;
if (i + 2 >= ca.length
|| !vid[0].equals(ca[i + 2].split("_")[0])) {
- if(ca.length > i + 1) {
- m = new SingleValueMap(vid[1], convertVariableValue(
- vid[2].charAt(0), ca[++i]));
+ if (ca.length > i + 1) {
+ m = new SingleValueMap(vid[1],
+ convertVariableValue(vid[2].charAt(0),
+ ca[++i]));
} else {
- m = new SingleValueMap(vid[1], convertVariableValue(vid[2].charAt(0), ""));
+ m = new SingleValueMap(vid[1],
+ convertVariableValue(vid[2].charAt(0), ""));
}
- }
- else {
+ } else {
m = new HashMap();
m.put(vid[1], convertVariableValue(vid[2].charAt(0),
ca[++i]));
val = Boolean.valueOf(strValue);
break;
}
-
- System.out.println("result: " + val + " of type " + (val == null ? "-" : val.getClass().toString()));
+
+ System.out.println("result: " + val + " of type "
+ + (val == null ? "-" : val.getClass().toString()));
return val;
}
// Find the window where the request is handled
String path = request.getPathInfo();
-
+
// Remove UIDL from the path
path = path.substring("/UIDL".length());
new OutputStreamWriter(out, "UTF-8")));
outWriter.print(")/*{");
outWriter.print("\"redirect\":{");
- outWriter.write("\"url\":\"" + logoutUrl
- + "\"}");
+ outWriter.write("\"url\":\"" + logoutUrl + "\"}");
outWriter.flush();
outWriter.close();
out.flush();
else
return new Locale(temp[0], temp[1], temp[2]);
}
+
+ /*
+ * Upload progress listener notifies upload component once when Jakarta
+ * FileUpload can determine content length. Used to detect files total size,
+ * uploads progress can be tracked inside upload.
+ */
+ private class UploadProgressListener implements ProgressListener {
+ Upload uploadComponent;
+ boolean updated = false;
+
+ public void setUpload(Upload u) {
+ uploadComponent = u;
+ }
+
+ public void update(long bytesRead, long contentLength, int items) {
+ if (!updated && uploadComponent != null) {
+ uploadComponent.setUploadSize(contentLength);
+ updated = true;
+ }
+ }
+ }
+
}
--- /dev/null
+package com.itmill.toolkit.tests;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import com.itmill.toolkit.terminal.StreamResource;
+import com.itmill.toolkit.ui.Button;
+import com.itmill.toolkit.ui.CustomComponent;
+import com.itmill.toolkit.ui.Label;
+import com.itmill.toolkit.ui.Layout;
+import com.itmill.toolkit.ui.Link;
+import com.itmill.toolkit.ui.OrderedLayout;
+import com.itmill.toolkit.ui.Panel;
+import com.itmill.toolkit.ui.ProgressIndicator;
+import com.itmill.toolkit.ui.Upload;
+import com.itmill.toolkit.ui.Button.ClickEvent;
+import com.itmill.toolkit.ui.Upload.FailedEvent;
+import com.itmill.toolkit.ui.Upload.FailedListener;
+import com.itmill.toolkit.ui.Upload.FinishedEvent;
+import com.itmill.toolkit.ui.Upload.FinishedListener;
+import com.itmill.toolkit.ui.Upload.StartedEvent;
+import com.itmill.toolkit.ui.Upload.StartedListener;
+import com.itmill.toolkit.ui.Upload.SucceededEvent;
+import com.itmill.toolkit.ui.Upload.SucceededListener;
+
+public class TestForUpload extends CustomComponent implements
+ Upload.FinishedListener, FailedListener,SucceededListener, Upload.ProgressListener, StartedListener {
+
+ Layout main = new OrderedLayout();
+
+ Buffer buffer = new Buffer();
+
+ Panel status = new Panel("Uploaded file:");
+
+ private Upload up;
+
+ private Label l;
+
+ private ProgressIndicator pi = new ProgressIndicator();
+
+ public TestForUpload() {
+ setCompositionRoot(main);
+ main.addComponent( new Label(
+ "This is a simple test for upload application. "
+ + "Upload should work with big files and concurrent "
+ + "requests should not be blocked. Button 'b' reads "
+ + "current state into label below it. TODO make "
+ + "streaming example/test where upload contents "
+ + "is read but not saved and memory consumption is "
+ + "verified low. TODO make test where contents is "
+ + "written to disk and verifiy low memory consumption."));
+
+ main.addComponent(new Label("Clicking on button b updates information about upload components status."));
+
+ up = new Upload("Upload", buffer);
+ up.setImmediate(true);
+ up.addListener((FinishedListener)this);
+ up.addListener((FailedListener) this);
+ up.addListener((SucceededListener) this);
+ up.addListener((StartedListener) this);
+
+
+ up.setProgressListener(this);
+
+ Button b = new Button("b", this, "readState");
+
+ main.addComponent(b);
+
+
+
+ main.addComponent(up);
+ l = new Label("Idle");
+ main.addComponent(l);
+
+ pi.setVisible(false);
+ pi.setPollingInterval(1000);
+ main.addComponent(pi);
+
+ status.setVisible(false);
+ main.addComponent(status);
+
+
+ Button restart = new Button("R");
+ restart.addListener(new Button.ClickListener() {
+
+ public void buttonClick(ClickEvent event) {
+ getApplication().close();
+ }
+ });
+ main.addComponent(restart);
+
+
+ }
+
+ public void readState() {
+ StringBuffer sb = new StringBuffer();
+
+ if (up.isUploading()) {
+ sb.append("Uploading...");
+ sb.append(up.getBytesRead());
+ sb.append("/");
+ sb.append(up.getUploadSize());
+ sb.append(" ");
+ sb.append(Math.round(100 * up.getBytesRead()
+ / (double) up.getUploadSize()));
+ sb.append("%");
+ } else {
+ sb.append("Idle");
+ }
+ l.setValue(sb.toString());
+ }
+
+ public void uploadFinished(FinishedEvent event) {
+ status.removeAllComponents();
+ if (buffer.getStream() == null)
+ status.addComponent(new Label(
+ "Upload finished, but output buffer is null!!"));
+ else {
+ status
+ .addComponent(new Label("<b>Name:</b> "
+ + event.getFilename(), Label.CONTENT_XHTML));
+ status.addComponent(new Label("<b>Mimetype:</b> "
+ + event.getMIMEType(), Label.CONTENT_XHTML));
+ status.addComponent(new Label("<b>Size:</b> " + event.getLength()
+ + " bytes.", Label.CONTENT_XHTML));
+
+ status.addComponent(new Link("Download " + buffer.getFileName(),
+ new StreamResource(buffer, buffer.getFileName(),
+ getApplication())));
+
+ status.setVisible(true);
+ }
+ }
+
+ public class Buffer implements StreamResource.StreamSource, Upload.Receiver {
+ ByteArrayOutputStream outputBuffer = null;
+
+ String mimeType;
+
+ String fileName;
+
+ public Buffer() {
+
+ }
+
+ public InputStream getStream() {
+ if (outputBuffer == null)
+ return null;
+ return new ByteArrayInputStream(outputBuffer.toByteArray());
+ }
+
+ /**
+ * @see com.itmill.toolkit.ui.Upload.Receiver#receiveUpload(String,
+ * String)
+ */
+ public OutputStream receiveUpload(String filename, String MIMEType) {
+ fileName = filename;
+ mimeType = MIMEType;
+ outputBuffer = new ByteArrayOutputStream();
+ return outputBuffer;
+ }
+
+ /**
+ * Returns the fileName.
+ *
+ * @return String
+ */
+ public String getFileName() {
+ return fileName;
+ }
+
+ /**
+ * Returns the mimeType.
+ *
+ * @return String
+ */
+ public String getMimeType() {
+ return mimeType;
+ }
+
+ }
+
+ public void uploadFailed(FailedEvent event) {
+ System.out.println(event);
+
+ System.out.println(event.getSource());
+
+ }
+
+ public void uploadSucceeded(SucceededEvent event) {
+ pi.setVisible(false);
+ l.setValue("Finished upload, idle");
+ System.out.println(event);
+ }
+
+ public void updateProgress(long readBytes, long contentLenght) {
+ pi.setValue(new Float(readBytes/(float)contentLenght));
+ }
+
+ public void uploadStarted(StartedEvent event) {
+ pi.setVisible(true);
+ l.setValue("Started uploading file " + event.getFilename());
+ }
+
+}
* @author IT Mill Ltd.
* @version
* @VERSION@
- * @since 3.1
+ * @since 4
*/
public class ProgressIndicator extends AbstractField implements Property,
Property.Viewer, Property.ValueChangeListener {
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. */
/**
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)
"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.
*
if (this.tabIndex >= 0)
target.addAttribute("tabindex", this.tabIndex);
+ target.addAttribute("state", isUploading);
+
+ target.addVariable(this, "fake", true);
+
target.addUploadStreamVariable(this, "stream");
}
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 });
}
/**
- * 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;
}
}
}
+ /**
+ * 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.
*
public void uploadSucceeded(SucceededEvent event);
}
+ /**
+ * 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.
*
removeListener(SucceededEvent.class, listener, UPLOAD_SUCCEEDED_METHOD);
}
+ /**
+ * Emit upload received event.
+ *
+ * @param filename
+ * @param MIMEType
+ * @param length
+ */
+ protected void fireStarted(String filename, String MIMEType) {
+ fireEvent(new Upload.StartedEvent(this, filename, MIMEType));
+ }
+
/**
* Emit upload received event.
*
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);
+ }
}