com.wcs.wcslib.vaadin.widget.multifileupload.client.VMultiUpload.java Source code

Java tutorial

Introduction

Here is the source code for com.wcs.wcslib.vaadin.widget.multifileupload.client.VMultiUpload.java

Source

/*
 * Copyright 2013 gergo.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.wcs.wcslib.vaadin.widget.multifileupload.client;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.core.client.Scheduler;
import com.google.gwt.core.client.Scheduler.ScheduledCommand;
import com.google.gwt.dom.client.InputElement;
import com.google.gwt.dom.client.Node;
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.FileUpload;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Panel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.xhr.client.ReadyStateChangeHandler;
import com.google.gwt.xhr.client.XMLHttpRequest;
import com.vaadin.client.ApplicationConnection;
import com.vaadin.client.Paintable;
import com.vaadin.client.UIDL;
import com.vaadin.client.VConsole;
import com.vaadin.client.ui.Icon;
import com.vaadin.client.ui.VButton;
import com.vaadin.client.ui.VNotification;
import com.vaadin.client.ui.dd.VHtml5File;
import java.util.Arrays;
import java.util.ListIterator;

/**
 * Upload counterpart with "multiple" support.
 *
 *
 * This is a modified version of org.vaadin.easyuploads.client.ui.VMultiUpload.java which is part of the EasyUploads
 * 7.0.0 Vaadin addon.
 *
 *
 * Not finished enough for extension.
 */
public class VMultiUpload extends SimplePanel implements Paintable {

    private long maxFileSize;
    private String sizeErrorMsg;
    private String mimeTypeErrorMsg;
    private List<String> acceptedMimeTypes;
    private InputElement input;

    private final class MyFileUpload extends FileUpload {

        public MyFileUpload() {
            getElement().setAttribute("multiple", "multiple");
        }

        @Override
        public void onBrowserEvent(Event event) {
            super.onBrowserEvent(event);
            if (event.getTypeInt() == Event.ONCHANGE && hasFiles()) {
                submit();
            }
        }

        public boolean hasFiles() {
            return getFileCount(getElement()) > 0;
        }
    }

    public static final native int getFileCount(Element el) /*-{
                                                            return el.files.length;
                                                            }-*/;

    public static final native VHtml5File getFile(Element el, int i) /*-{
                                                                     return el.files[i];
                                                                     }-*/;

    public static final String CLASSNAME = "v-upload";
    private static final String DELIM = "---xXx---";
    /**
     * FileUpload component that opens native OS dialog to select file.
     */
    MyFileUpload fu = new MyFileUpload();
    Panel panel = new FlowPanel();
    ApplicationConnection client;
    private String paintableId;
    /**
     * Button that initiates uploading
     */
    public final VButton submitButton;
    public Icon icon;
    private boolean enabled = true;
    private String receiverUri;
    private ReadyStateChangeHandler readyStateChangeHandler = new ReadyStateChangeHandler() {
        @Override
        public void onReadyStateChange(XMLHttpRequest xhr) {
            if (xhr.getReadyState() == XMLHttpRequest.DONE) {
                xhr.clearOnReadyStateChange();

                Scheduler.get().scheduleDeferred(new ScheduledCommand() {
                    @Override
                    public void execute() {
                        if (isAttached() && !fileQueue.isEmpty()) {
                            client.updateVariable(paintableId, "ready", true, true);
                            postNextFileFromQueue();
                        }
                    }
                });
            }
        }
    };

    ;

    public VMultiUpload() {
        super(com.google.gwt.dom.client.Document.get().createDivElement());

        setWidget(panel);
        panel.add(fu);
        submitButton = new VButton();
        submitButton.addClickHandler(new ClickHandler() {
            @Override
            public void onClick(ClickEvent event) {
                // fire click on upload (eg. focused button and hit space)
                fireNativeClick(fu.getElement());
            }
        });
        panel.add(submitButton);

        setStyleName(CLASSNAME);
        fu.sinkEvents(Event.ONCHANGE);
        fu.sinkEvents(Event.ONFOCUS);
        addStyleName(CLASSNAME + "-immediate");
    }

    @Override
    public void updateFromUIDL(UIDL uidl, ApplicationConnection client) {
        if (client.updateComponent(this, uidl, true)) {
            return;
        }
        addStyleName(CLASSNAME + "-immediate");

        this.client = client;
        paintableId = uidl.getId();
        receiverUri = client.translateVaadinUri(uidl.getStringVariable("target"));
        submitButton.setText(uidl.getStringAttribute("buttoncaption"));
        fu.setName(paintableId + "_file");

        if (uidl.hasAttribute("enabled")) {
            if (uidl.getBooleanAttribute("enabled")) {
                enableUpload();
            } else {
                disableUpload();
            }
        }

        if (uidl.hasAttribute("maxFileSize")) {
            maxFileSize = uidl.getLongAttribute("maxFileSize");
        }
        if (uidl.hasAttribute("sizeErrorMsg")) {
            sizeErrorMsg = uidl.getStringAttribute("sizeErrorMsg");
        }
        if (uidl.hasAttribute("mimeTypeErrorMsg")) {
            mimeTypeErrorMsg = uidl.getStringAttribute("mimeTypeErrorMsg");
        }
        if (uidl.hasAttribute("acceptFilter")) {
            getInput().setAccept(uidl.getStringAttribute("acceptFilter"));
        }
        if (uidl.hasAttribute("acceptedMimeTypes")) {
            acceptedMimeTypes = Arrays.asList(uidl.getStringArrayAttribute("acceptedMimeTypes"));
        }
        if (uidl.hasAttribute("interruptedFileIds")) {
            removeFromFileQueue(uidl.getIntArrayAttribute("interruptedFileIds"));
        }
        if (uidl.hasAttribute("ready")) {
            postNextFileFromQueue();
        }
    }

    private InputElement getInput() {
        if (input == null || !getElement().isOrHasChild((Node) input)) {
            input = fu.getElement().cast();
        }
        return input;
    }

    private void removeFromFileQueue(int[] interruptedFileIds) {
        for (ListIterator<FileWrapper> it = fileQueue.listIterator(); it.hasNext();) {
            FileWrapper fileWrapper = it.next();
            for (int id : interruptedFileIds) {
                if (fileWrapper.getId() == id) {
                    it.remove();
                    break;
                }
            }
        }
    }

    private void postNextFileFromQueue() {
        if (!fileQueue.isEmpty()) {
            final VHtml5File file = fileQueue.remove(0).getFile();
            ExtendedXHR extendedXHR = (ExtendedXHR) ExtendedXHR.create();
            extendedXHR.setOnReadyStateChange(readyStateChangeHandler);
            extendedXHR.open("POST", receiverUri);
            extendedXHR.postFile(file);
            new Timer() {
                @Override
                public void run() {
                    // TODO poll for start or modify response so that we
                    // receive headers received
                    client.sendPendingVariableChanges();
                }
            }.schedule(700);
        }
    }

    static class ExtendedXHR extends XMLHttpRequest {

        protected ExtendedXHR() {
        }

        public final native void postFile(VHtml5File file) /*-{
                                                           this.setRequestHeader('Accept', 'text/html,vaadin/filexhr');
                                                           this.setRequestHeader('Content-Type', 'multipart/form-data');
                                                           this.send(file);
                                                           }-*/;
    }

    private static native void fireNativeClick(Element element) /*-{
                                                                element.click();
                                                                }-*/;

    protected void disableUpload() {
        submitButton.setEnabled(false);
        // Cannot disable the fileupload while submitting or the file won't
        // be submitted at all
        fu.getElement().setPropertyBoolean("disabled", true);
        enabled = false;
    }

    protected void enableUpload() {
        submitButton.setEnabled(true);
        fu.getElement().setPropertyBoolean("disabled", false);
        enabled = true;
    }

    private boolean isValidFileSize(VHtml5File file, StringBuilder errorMsg) {
        if (file.getSize() > maxFileSize || file.getSize() <= 0) {
            String formattedErrorMsg = UploadClientUtil.getSizeErrorMessage(sizeErrorMsg, maxFileSize,
                    file.getSize(), file.getName());

            errorMsg.append(formattedErrorMsg).append("<br/>");
            return false;
        }
        return true;
    }

    private boolean isValidMimeType(VHtml5File file, StringBuilder errorMsg) {
        if (acceptedMimeTypes != null && !acceptedMimeTypes.isEmpty()
                && !acceptedMimeTypes.contains(file.getType())) {
            String formattedErrorMsg = UploadClientUtil.getMimeTypeErrorMessage(mimeTypeErrorMsg, file.getName());
            errorMsg.append(formattedErrorMsg).append("<br/>");
            return false;
        }
        return true;
    }

    private void submit() {
        if (!enabled) {
            VConsole.log("Submit cancelled (disabled)");
            return;
        }
        int files = getFileCount(fu.getElement());
        List<String> filedetails = new ArrayList<String>();
        StringBuilder errorMsg = new StringBuilder();
        for (int i = 0; i < files; i++) {
            VHtml5File file = getFile(fu.getElement(), i);
            if (!isValidFileSize(file, errorMsg) || !isValidMimeType(file, errorMsg)) {
                continue;
            }

            FileWrapper wrapper = queueFilePost(file);
            filedetails.add(wrapper.serialize());
        }
        client.updateVariable(paintableId, "filequeue", filedetails.toArray(new String[filedetails.size()]), true);

        if (!errorMsg.toString().isEmpty()) {
            VNotification.createNotification(1000, client.getUIConnector().getWidget()).show(errorMsg.toString(),
                    VNotification.CENTERED, "warning");
        }
        disableUpload();
    }

    private List<FileWrapper> fileQueue = new ArrayList<FileWrapper>();
    private long id;

    private FileWrapper queueFilePost(VHtml5File file) {
        FileWrapper fileWrapper = new FileWrapper(++id, file);
        fileQueue.add(fileWrapper);
        return fileWrapper;
    }

    private static final class FileWrapper {

        private long id;
        private VHtml5File file;

        public FileWrapper(long id, VHtml5File file) {
            this.id = id;
            this.file = file;
        }

        public long getId() {
            return id;
        }

        public VHtml5File getFile() {
            return file;
        }

        public String serialize() {
            Number size = file.getSize();
            String name = file.getName();
            String type = file.getType();
            return id + DELIM + size + DELIM + name + DELIM + type + DELIM;
        }
    }
}