]> source.dussan.org Git - vaadin-framework.git/commitdiff
multiple upload related enhancements
authorMatti Tahvonen <matti.tahvonen@itmill.com>
Wed, 5 Aug 2009 07:48:43 +0000 (07:48 +0000)
committerMatti Tahvonen <matti.tahvonen@itmill.com>
Wed, 5 Aug 2009 07:48:43 +0000 (07:48 +0000)
 - implemented interruption of upload #963
 - added generics
 - changed deprecated gwt methods to 1.6 handlers
 - immediate mode now works (also styled as "one button upload")

svn changeset:8442/svn branch:6.0

WebContent/VAADIN/themes/base/styles.css
WebContent/VAADIN/themes/base/upload/upload.css [new file with mode: 0644]
WebContent/VAADIN/themes/reindeer/styles.css
WebContent/VAADIN/themes/runo/styles.css
src/com/vaadin/terminal/gwt/client/ui/VUpload.java
src/com/vaadin/tests/TestForStyledUpload.java [new file with mode: 0644]
src/com/vaadin/ui/Upload.java

index a75762c0f87d5cc5899f89270fd9c147eeecb228..e98bef219cb43a813383172ff03f384d498ad5fa 100644 (file)
@@ -1436,6 +1436,30 @@ div.v-tree-node-leaf {
        clear: left;
 }
 
+/* ./WebContent/VAADIN/themes/base/upload/upload.css */
+.v-upload-immediate {
+       position: relative;
+       width: 10em;
+       margin:0;
+}
+
+.v-upload-immediate input {
+       opacity: 0;
+       filter: alpha(opacity=0);
+       z-index:2;
+       position: absolute;
+       right:0;
+       height:21px;
+       text-align: right;
+}
+.v-upload-immediate button {
+       position:relative;
+       left:0;
+       top:0;
+       width:100%;
+}
+  
+
 /* ./WebContent/VAADIN/themes/base/window/window.css */
 .v-window {
        background: #fff;
diff --git a/WebContent/VAADIN/themes/base/upload/upload.css b/WebContent/VAADIN/themes/base/upload/upload.css
new file mode 100644 (file)
index 0000000..ba96537
--- /dev/null
@@ -0,0 +1,22 @@
+.v-upload-immediate {
+       position: relative;
+       width: 10em;
+       margin:0;
+}
+
+.v-upload-immediate input {
+       opacity: 0;
+       filter: alpha(opacity=0);
+       z-index:2;
+       position: absolute;
+       right:0;
+       height:21px;
+       text-align: right;
+}
+.v-upload-immediate button {
+       position:relative;
+       left:0;
+       top:0;
+       width:100%;
+}
+  
\ No newline at end of file
index 4df54dd3edf35dae1b6c45642eb5ddf7831b0074..b5bf3402e52702a6e981d460aaefd7fbf0e22f5e 100644 (file)
@@ -1436,6 +1436,30 @@ div.v-tree-node-leaf {
        clear: left;
 }
 
+/* ./WebContent/VAADIN/themes/base/upload/upload.css */
+.v-upload-immediate {
+       position: relative;
+       width: 10em;
+       margin:0;
+}
+
+.v-upload-immediate input {
+       opacity: 0;
+       filter: alpha(opacity=0);
+       z-index:2;
+       position: absolute;
+       right:0;
+       height:21px;
+       text-align: right;
+}
+.v-upload-immediate button {
+       position:relative;
+       left:0;
+       top:0;
+       width:100%;
+}
+  
+
 /* ./WebContent/VAADIN/themes/base/window/window.css */
 .v-window {
        background: #fff;
index a1633d5522063de710a0f17fd76cf256cb6a1a06..639e4cc9926e8cb8b11b7e9d5a0ac44e08e3297b 100644 (file)
@@ -1436,6 +1436,30 @@ div.v-tree-node-leaf {
        clear: left;
 }
 
+/* ./WebContent/VAADIN/themes/base/upload/upload.css */
+.v-upload-immediate {
+       position: relative;
+       width: 10em;
+       margin:0;
+}
+
+.v-upload-immediate input {
+       opacity: 0;
+       filter: alpha(opacity=0);
+       z-index:2;
+       position: absolute;
+       right:0;
+       height:21px;
+       text-align: right;
+}
+.v-upload-immediate button {
+       position:relative;
+       left:0;
+       top:0;
+       width:100%;
+}
+  
+
 /* ./WebContent/VAADIN/themes/base/window/window.css */
 .v-window {
        background: #fff;
index 666652a15a979e8ab49e285c9dc9debbb9561e7d..117d3ea26796e8b54ac0d0939af18d298ed148cd 100644 (file)
@@ -4,30 +4,53 @@
 
 package com.vaadin.terminal.gwt.client.ui;
 
+import com.google.gwt.event.dom.client.ClickEvent;
+import com.google.gwt.event.dom.client.ClickHandler;
+import com.google.gwt.user.client.Element;
+import com.google.gwt.user.client.Event;
 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.FlowPanel;
-import com.google.gwt.user.client.ui.FormHandler;
 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.Hidden;
 import com.google.gwt.user.client.ui.Panel;
-import com.google.gwt.user.client.ui.Widget;
+import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
+import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
 import com.vaadin.terminal.gwt.client.ApplicationConnection;
 import com.vaadin.terminal.gwt.client.Paintable;
 import com.vaadin.terminal.gwt.client.UIDL;
 
-public class VUpload extends FormPanel implements Paintable, ClickListener,
-        FormHandler {
+public class VUpload extends FormPanel implements Paintable,
+        SubmitCompleteHandler, SubmitHandler {
+
+    private final class MyFileUpload extends FileUpload {
+        @Override
+        public void onBrowserEvent(Event event) {
+            super.onBrowserEvent(event);
+            if (event.getTypeInt() == Event.ONCHANGE) {
+                if (immediate && fu.getFilename() != null
+                        && !"".equals(fu.getFilename())) {
+                    submit();
+                }
+            } else if (event.getTypeInt() == Event.ONFOCUS) {
+                // IE and user has clicked on hidden textarea part of upload
+                // field. Manually open file selector, other browsers do it by
+                // default.
+                fireNativeClick(fu.getElement());
+                // also remove focus to enable hack if user presses cancel
+                // button
+                fireNativeBlur(fu.getElement());
+            }
+        }
+    }
 
     public static final String CLASSNAME = "v-upload";
 
     /**
      * FileUpload component that opens native OS dialog to select file.
      */
-    FileUpload fu = new FileUpload();
+    FileUpload fu = new MyFileUpload();
 
     Panel panel = new FlowPanel();
 
@@ -56,18 +79,34 @@ public class VUpload extends FormPanel implements Paintable, ClickListener,
 
     private boolean enabled = true;
 
+    private boolean immediate;
+
+    private Hidden maxfilesize = new Hidden();
+
     public VUpload() {
         super();
         setEncoding(FormPanel.ENCODING_MULTIPART);
         setMethod(FormPanel.METHOD_POST);
 
         setWidget(panel);
+        panel.add(maxfilesize);
         panel.add(fu);
         submitButton = new Button();
-        submitButton.addClickListener(this);
+        submitButton.setStyleName("v-button");
+        submitButton.addClickHandler(new ClickHandler() {
+            public void onClick(ClickEvent event) {
+                if (immediate) {
+                    // fire click on upload (eg. focused button and hit space)
+                    fireNativeClick(fu.getElement());
+                } else {
+                    submit();
+                }
+            }
+        });
         panel.add(submitButton);
 
-        addFormHandler(this);
+        addSubmitCompleteHandler(this);
+        addSubmitHandler(this);
 
         setStyleName(CLASSNAME);
     }
@@ -76,10 +115,12 @@ public class VUpload extends FormPanel implements Paintable, ClickListener,
         if (client.updateComponent(this, uidl, true)) {
             return;
         }
+        setImmediate(uidl.getBooleanAttribute("immediate"));
         this.client = client;
         paintableId = uidl.getId();
         setAction(client.getAppUri());
-        submitButton.setText(uidl.getStringAttribute("buttoncaption"));
+        submitButton.setHTML("<span class=\"v-button-caption\">"
+                + uidl.getStringAttribute("buttoncaption") + "</span>");
         fu.setName(paintableId + "_file");
 
         if (uidl.hasAttribute("disabled") || uidl.hasAttribute("readonly")) {
@@ -87,16 +128,76 @@ public class VUpload extends FormPanel implements Paintable, ClickListener,
         } else if (uidl.getBooleanAttribute("state")) {
             enableUploaod();
         }
+    }
 
+    private void setImmediate(boolean booleanAttribute) {
+        if (immediate != booleanAttribute) {
+            immediate = booleanAttribute;
+            if (immediate) {
+                fu.sinkEvents(Event.ONCHANGE);
+                fu.sinkEvents(Event.ONFOCUS);
+            }
+        }
+        setStyleName(getElement(), CLASSNAME + "-immediate", immediate);
     }
 
-    public void onClick(Widget sender) {
-        submit();
+    private static native void fireNativeClick(Element element)
+    /*-{
+        element.click();
+    }-*/;
+
+    private static native void fireNativeBlur(Element element)
+    /*-{
+        element.blur();
+    }-*/;
+
+    protected void disableUpload() {
+        submitButton.setEnabled(false);
+        fu.setVisible(false);
+        enabled = false;
     }
 
-    public void onSubmit(FormSubmitEvent event) {
+    protected void enableUploaod() {
+        submitButton.setEnabled(true);
+        fu.setVisible(true);
+        enabled = true;
+    }
+
+    /**
+     * Re-creates file input field and populates panel. This is needed as we
+     * want to clear existing values from our current file input field.
+     */
+    private void rebuildPanel() {
+        panel.remove(submitButton);
+        panel.remove(fu);
+        fu = new MyFileUpload();
+        fu.setName(paintableId + "_file");
+        fu.setVisible(enabled);
+        panel.add(fu);
+        panel.add(submitButton);
+        if (immediate) {
+            fu.sinkEvents(Event.ONCHANGE);
+        }
+    }
+
+    public void onSubmitComplete(SubmitCompleteEvent event) {
+        if (client != null) {
+            if (t != null) {
+                t.cancel();
+            }
+            ApplicationConnection.getConsole().log("Submit complete");
+            client.sendPendingVariableChanges();
+        }
+
+        rebuildPanel();
+
+        submitted = false;
+        enableUploaod();
+    }
+
+    public void onSubmit(SubmitEvent event) {
         if (fu.getFilename().length() == 0 || submitted || !enabled) {
-            event.setCancelled(true);
+            event.cancel();
             ApplicationConnection
                     .getConsole()
                     .log(
@@ -125,28 +226,4 @@ public class VUpload extends FormPanel implements Paintable, ClickListener,
         t.schedule(800);
     }
 
-    protected void disableUpload() {
-        submitButton.setEnabled(false);
-        fu.setVisible(false);
-        enabled = false;
-    }
-
-    protected void enableUploaod() {
-        submitButton.setEnabled(true);
-        fu.setVisible(true);
-        enabled = true;
-    }
-
-    public void onSubmitComplete(FormSubmitCompleteEvent event) {
-        if (client != null) {
-            if (t != null) {
-                t.cancel();
-            }
-            ApplicationConnection.getConsole().log("Submit complete");
-            client.sendPendingVariableChanges();
-        }
-        submitted = false;
-        enableUploaod();
-    }
-
 }
diff --git a/src/com/vaadin/tests/TestForStyledUpload.java b/src/com/vaadin/tests/TestForStyledUpload.java
new file mode 100644 (file)
index 0000000..0e4933d
--- /dev/null
@@ -0,0 +1,288 @@
+/* 
+@ITMillApache2LicenseForJavaFiles@
+ */
+
+package com.vaadin.tests;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.management.ManagementFactory;
+import java.lang.management.MemoryMXBean;
+
+import com.vaadin.Application;
+import com.vaadin.terminal.StreamResource;
+import com.vaadin.ui.Button;
+import com.vaadin.ui.Label;
+import com.vaadin.ui.Layout;
+import com.vaadin.ui.Link;
+import com.vaadin.ui.Panel;
+import com.vaadin.ui.ProgressIndicator;
+import com.vaadin.ui.Upload;
+import com.vaadin.ui.VerticalLayout;
+import com.vaadin.ui.Window;
+import com.vaadin.ui.Button.ClickEvent;
+import com.vaadin.ui.Upload.FailedEvent;
+import com.vaadin.ui.Upload.FailedListener;
+import com.vaadin.ui.Upload.FinishedEvent;
+import com.vaadin.ui.Upload.FinishedListener;
+import com.vaadin.ui.Upload.StartedEvent;
+import com.vaadin.ui.Upload.StartedListener;
+import com.vaadin.ui.Upload.SucceededEvent;
+import com.vaadin.ui.Upload.SucceededListener;
+
+public class TestForStyledUpload extends Application implements
+        Upload.FinishedListener, FailedListener, SucceededListener,
+        StartedListener {
+
+    Layout main = new VerticalLayout();
+
+    TmpFileBuffer buffer = new TmpFileBuffer();
+
+    Panel status = new Panel("Uploaded file:");
+
+    private final Upload up;
+
+    private final Label l;
+
+    private final Label transferred = new Label("");
+
+    private final ProgressIndicator pi = new ProgressIndicator();
+
+    private final Label memoryStatus;
+
+    public TestForStyledUpload() {
+        main
+                .addComponent(new Label(
+                        "Clicking on button b updates information about upload components status or same with garbage collector."));
+
+        up = new Upload(null, buffer);
+        up.setButtonCaption("Select file");
+        up.setImmediate(true);
+        up.addListener((FinishedListener) this);
+        up.addListener((FailedListener) this);
+        up.addListener((SucceededListener) this);
+        up.addListener((StartedListener) this);
+
+        up.addListener(new Upload.ProgressListener() {
+
+            public void updateProgress(long readBytes, long contentLenght) {
+                pi.setValue(new Float(readBytes / (float) contentLenght));
+
+                refreshMemUsage();
+
+                transferred.setValue("Transferred " + readBytes + " of "
+                        + contentLenght);
+            }
+
+        });
+
+        final Button b = new Button("Update status", this, "readState");
+
+        final Button c = new Button("Update status with gc", this, "gc");
+
+        main.addComponent(up);
+        l = new Label("Idle");
+        main.addComponent(l);
+
+        pi.setVisible(false);
+        pi.setPollingInterval(300);
+        main.addComponent(pi);
+        main.addComponent(transferred);
+
+        memoryStatus = new Label();
+        main.addComponent(memoryStatus);
+
+        status.setVisible(false);
+        main.addComponent(status);
+
+        Button cancel = new Button("Cancel current upload");
+        cancel.addListener(new Button.ClickListener() {
+            public void buttonClick(ClickEvent event) {
+                buffer.cancel();
+            }
+        });
+
+        main.addComponent(cancel);
+
+        final Button restart = new Button("Restart demo application");
+        restart.addListener(new Button.ClickListener() {
+
+            public void buttonClick(ClickEvent event) {
+                TestForStyledUpload.this.close();
+            }
+        });
+        main.addComponent(restart);
+        main.addComponent(b);
+        main.addComponent(c);
+
+    }
+
+    public void gc() {
+        Runtime.getRuntime().gc();
+        readState();
+    }
+
+    public void readState() {
+        final 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());
+        refreshMemUsage();
+    }
+
+    public void uploadFinished(FinishedEvent event) {
+        status.removeAllComponents();
+        final InputStream stream = buffer.getStream();
+        if (stream == 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(), this)));
+
+            status.setVisible(true);
+        }
+    }
+
+    public interface Buffer extends StreamResource.StreamSource,
+            Upload.Receiver {
+
+        String getFileName();
+    }
+
+    public class TmpFileBuffer implements Buffer {
+        String mimeType;
+
+        String fileName;
+
+        private File file;
+
+        private FileInputStream stream;
+
+        public TmpFileBuffer() {
+            final String tempFileName = "upload_tmpfile_"
+                    + System.currentTimeMillis();
+            try {
+                file = File.createTempFile(tempFileName, null);
+            } catch (final IOException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+
+        }
+
+        public void cancel() {
+            up.interruptUpload();
+        }
+
+        public InputStream getStream() {
+            if (file == null) {
+                return null;
+            }
+            try {
+                stream = new FileInputStream(file);
+                return stream;
+            } catch (final FileNotFoundException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            return null;
+        }
+
+        /**
+         * @see com.vaadin.ui.Upload.Receiver#receiveUpload(String, String)
+         */
+        public OutputStream receiveUpload(String filename, String MIMEType) {
+            fileName = filename;
+            mimeType = MIMEType;
+            try {
+                return new FileOutputStream(file);
+            } catch (final FileNotFoundException e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+            return null;
+        }
+
+        /**
+         * 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) {
+        pi.setVisible(false);
+        l.setValue("Upload was interrupted");
+    }
+
+    public void uploadSucceeded(SucceededEvent event) {
+        pi.setVisible(false);
+        l.setValue("Finished upload, idle");
+        System.out.println(event);
+    }
+
+    private void refreshMemUsage() {
+        // memoryStatus.setValue("Not available in Java 1.4");
+        StringBuffer mem = new StringBuffer();
+        MemoryMXBean mmBean = ManagementFactory.getMemoryMXBean();
+        mem.append("Heap (M):");
+        mem.append(mmBean.getHeapMemoryUsage().getUsed() / 1048576);
+        mem.append(" | Non-Heap (M):");
+        mem.append(mmBean.getNonHeapMemoryUsage().getUsed() / 1048576);
+        memoryStatus.setValue(mem.toString());
+
+    }
+
+    public void uploadStarted(StartedEvent event) {
+        pi.setVisible(true);
+        l.setValue("Started uploading file " + event.getFilename());
+    }
+
+    @Override
+    public void init() {
+        Window w = new Window();
+        w.setTheme("runo");
+        w.addComponent(main);
+        setMainWindow(w);
+
+    }
+
+}
index 70e16e1dedf686810c74699084cb3ffbc5835dcb..cdea1e6ce3dbc68dd58d1df7c4b8752401fb5988 100644 (file)
@@ -4,6 +4,7 @@
 
 package com.vaadin.ui;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
@@ -20,13 +21,16 @@ import com.vaadin.terminal.UploadStream;
 /**
  * Component for uploading files from client to server.
  * 
+ * <p>
  * The visible component consists of a file name input box and a browse button
  * and an upload submit button to start uploading.
  * 
+ * <p>
  * The Upload component needs a java.io.OutputStream to write the uploaded data.
  * You need to implement the Upload.Receiver interface and return the output
  * stream in the receiveUpload() method.
  * 
+ * <p>
  * You can get an event regarding starting (StartedEvent), progress
  * (ProgressEvent), and finishing (FinishedEvent) of upload by implementing
  * StartedListener, ProgressListener, and FinishedListener, respectively. The
@@ -34,10 +38,16 @@ import com.vaadin.terminal.UploadStream;
  * to separate between these two cases, you can use SucceededListener
  * (SucceededEvenet) and FailedListener (FailedEvent).
  * 
+ * <p>
  * The upload component does not itself show upload progress, but you can use
  * the ProgressIndicator for providing progress feedback by implementing
  * ProgressListener and updating the indicator in updateProgress().
  * 
+ * <p>
+ * Setting upload component immediate initiates the upload as soon as a file is
+ * selected, instead of the common pattern of file selection field and upload
+ * button.
+ * 
  * @author IT Mill Ltd.
  * @version
  * @VERSION@
@@ -81,7 +91,9 @@ public class Upload extends AbstractComponent implements Component.Focusable {
      * upload
      */
     private ProgressListener progressListener;
-    private LinkedHashSet progressListeners;
+    private LinkedHashSet<ProgressListener> progressListeners;
+
+    private boolean interrupted = false;
 
     /* TODO: Add a default constructor, receive to temp file. */
 
@@ -169,6 +181,9 @@ public class Upload extends AbstractComponent implements Component.Focusable {
                         fireUpdateProgress(totalBytes, contentLength);
                     }
                 }
+                if (interrupted) {
+                    throw new Exception("Upload interrupted by other thread");
+                }
             }
 
             // upload successful
@@ -182,8 +197,15 @@ public class Upload extends AbstractComponent implements Component.Focusable {
         } catch (final Exception e) {
             synchronized (application) {
                 // Download interrupted
+                try {
+                    // still try to close output stream
+                    out.close();
+                } catch (IOException e1) {
+                    // NOP
+                }
                 fireUploadInterrupted(filename, type, totalBytes, e);
                 endUpload();
+                interrupted = false;
             }
         }
     }
@@ -697,7 +719,7 @@ public class Upload extends AbstractComponent implements Component.Focusable {
      */
     public void addListener(ProgressListener listener) {
         if (progressListeners == null) {
-            progressListeners = new LinkedHashSet();
+            progressListeners = new LinkedHashSet<ProgressListener>();
         }
         progressListeners.add(listener);
     }
@@ -792,8 +814,9 @@ public class Upload extends AbstractComponent implements Component.Focusable {
         // this is implemented differently than other listeners to maintain
         // backwards compatibility
         if (progressListeners != null) {
-            for (Iterator it = progressListeners.iterator(); it.hasNext();) {
-                ProgressListener l = (ProgressListener) it.next();
+            for (Iterator<ProgressListener> it = progressListeners.iterator(); it
+                    .hasNext();) {
+                ProgressListener l = it.next();
                 l.updateProgress(totalBytes, contentLength);
             }
         }
@@ -880,13 +903,24 @@ public class Upload extends AbstractComponent implements Component.Focusable {
         isUploading = true;
     }
 
+    /**
+     * Interrupts the upload currently being received. The interruption will be
+     * done by the receiving tread so this method will return immediately and
+     * the actual interrupt will happen a bit later.
+     */
+    public void interruptUpload() {
+        if (isUploading) {
+            interrupted = true;
+        }
+    }
+
     /**
      * Go into state where new uploading can begin.
      * 
      * Warning: this is an internal method used by the framework and should not
      * be used by user of the Upload component.
      */
-    public void endUpload() {
+    private void endUpload() {
         isUploading = false;
         contentLength = -1;
     }
@@ -960,11 +994,17 @@ public class Upload extends AbstractComponent implements Component.Focusable {
     }
 
     /**
-     * File uploads usually have button that starts actual upload progress. This
-     * method is used to set text in that button.
+     * In addition to the actual file chooser, upload components have button
+     * that starts actual upload progress. This method is used to set text in
+     * that button.
+     * 
+     * <p>
+     * <strong>Note</strong> the string given is set as is to the button. HTML
+     * formatting is not stripped. Be sure to properly validate your value
+     * according to your needs.
      * 
      * @param buttonCaption
-     *            text for uploads button.
+     *            text for upload components button.
      */
     public void setButtonCaption(String buttonCaption) {
         this.buttonCaption = buttonCaption;