org.bonitasoft.forms.client.view.widget.FileUploadWidget.java Source code

Java tutorial

Introduction

Here is the source code for org.bonitasoft.forms.client.view.widget.FileUploadWidget.java

Source

/**
 * Copyright (C) 2009 BonitaSoft S.A.
 * BonitaSoft, 31 rue Gustave Eiffel - 38000 Grenoble
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2.0 of the License, or
 * (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package org.bonitasoft.forms.client.view.widget;

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

import org.bonitasoft.forms.client.i18n.FormsResourceBundle;
import org.bonitasoft.forms.client.model.FileWidgetInputType;
import org.bonitasoft.forms.client.model.ReducedFormFieldAvailableValue;
import org.bonitasoft.forms.client.view.SupportedFieldTypes;
import org.bonitasoft.forms.client.view.common.DOMUtils;
import org.bonitasoft.forms.client.view.common.RpcFormsServices;

import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.FormElement;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FormPanel;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitCompleteHandler;
import com.google.gwt.user.client.ui.FormPanel.SubmitEvent;
import com.google.gwt.user.client.ui.FormPanel.SubmitHandler;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.TextBox;

/**
 * Widget displaying either a file upload input if its initial value is null or a download link and file upload input to overide the current file
 *
 * @author Anthony Birembaut
 */
public class FileUploadWidget extends Composite implements ValueChangeHandler<Boolean> {

    /**
     * The URL document type
     */
    public static final String URL_DOCUMENT_TYPE = "URL";

    /**
     * The file document type
     */
    public static final String FILE_DOCUMENT_TYPE = "file";

    /**
     * the flow panel used to display the widgets
     */
    protected FlowPanel flowPanel;

    /**
     * the form panel used to display the widget
     */
    protected FormPanel formPanel;

    protected FlowPanel buttonPanel;

    protected Label cancelLabel;

    protected Label modifyLabel;

    protected Label removeLabel;

    protected FileDownloadWidget fileDownloadWidget;

    protected FileUpload fileUpload;

    protected Image loadingImage;

    protected String uploadedFilePath;

    protected String fileUploadFormName;

    protected long attachmentId;

    protected String attachmentName;

    protected FlowPanel filePanel;

    protected TextBox urlTextBox;

    protected RadioButtonGroupWidget radioButtonGroupWidget;

    protected FileWidgetInputType fileWidgetInputType;

    protected boolean isInitialContentFile;

    /**
     * Constructor
     *
     * @param contextMap
     * @param fieldId
     * @param fileWidgetInputType
     * @param valueType
     * @param attachmentId
     * @param attachmentName
     * @param value
     * @param hasImagePreview
     * @param isElementOfMultipleWidget
     */
    public FileUploadWidget(final String formID, final Map<String, Object> contextMap, final String fieldId,
            final FileWidgetInputType fileWidgetInputType, final String valueType, final long attachmentId,
            final String attachmentName, final String value, final boolean hasImagePreview) {

        this.fileWidgetInputType = fileWidgetInputType;
        this.attachmentId = attachmentId;
        this.attachmentName = attachmentName;
        if (attachmentName != null) {
            fileUploadFormName = attachmentName;
        } else {
            fileUploadFormName = fieldId;
        }
        isInitialContentFile = SupportedFieldTypes.JAVA_FILE_CLASSNAME.equals(valueType);

        flowPanel = new FlowPanel();

        if (isValidInputType(fileWidgetInputType, value)) {
            buildView(formID, contextMap, fieldId, valueType, value, hasImagePreview);
        }
        initWidget(flowPanel);
    }

    protected void buildView(final String formID, final Map<String, Object> contextMap, final String fieldId,
            final String valueType, final String value, final boolean hasImagePreview) {
        if (FileWidgetInputType.ALL.equals(fileWidgetInputType)) {

            final List<ReducedFormFieldAvailableValue> availableValues = new ArrayList<ReducedFormFieldAvailableValue>();
            availableValues.add(
                    new ReducedFormFieldAvailableValue(FormsResourceBundle.getMessages().url(), URL_DOCUMENT_TYPE));
            availableValues.add(new ReducedFormFieldAvailableValue(FormsResourceBundle.getMessages().file(),
                    FILE_DOCUMENT_TYPE));
            final String initialRadioButton;
            if (isInitialContentFile) {
                initialRadioButton = FILE_DOCUMENT_TYPE;
            } else {
                initialRadioButton = URL_DOCUMENT_TYPE;
            }
            radioButtonGroupWidget = new RadioButtonGroupWidget(fieldId + "_document_type", availableValues,
                    initialRadioButton, "bonita_form_radio_inline", false, true);
            radioButtonGroupWidget.addValueChangeHandler(this);
            flowPanel.add(radioButtonGroupWidget);
            final FlowPanel clearFloatPanel = new FlowPanel();
            clearFloatPanel.setStyleName("bonita_clear_float");
            flowPanel.add(clearFloatPanel);
        }

        if (!FileWidgetInputType.URL.equals(fileWidgetInputType)) {
            createFileUploadForm(fileUploadFormName);

            filePanel = new FlowPanel();

            fileDownloadWidget = new FileDownloadWidget(formID, contextMap, valueType, attachmentId,
                    hasImagePreview);

            loadingImage = new Image("themeResource?theme=portal&location=images/ajax-loader.gif");
            loadingImage.setTitle(FormsResourceBundle.getMessages().uploadingLabel());

            buttonPanel = new FlowPanel();
            cancelLabel = new Label();
            cancelLabel.setText(FormsResourceBundle.getMessages().cancelButtonLabel());
            cancelLabel.setTitle(FormsResourceBundle.getMessages().cancelButtonTitle());
            cancelLabel.setStyleName("bonita_upload_button");
            modifyLabel = new Label();
            modifyLabel.setText(FormsResourceBundle.getMessages().modifyButtonLabel());
            modifyLabel.setTitle(FormsResourceBundle.getMessages().modifyButtonTitle());
            modifyLabel.setStyleName("bonita_upload_button");
            removeLabel = new Label();
            removeLabel.setText(FormsResourceBundle.getMessages().removeButtonLabel());
            removeLabel.setTitle(FormsResourceBundle.getMessages().removeButtonTitle());
            removeLabel.setStyleName("bonita_upload_button");

            buttonPanel.add(cancelLabel);
            buttonPanel.add(modifyLabel);
            buttonPanel.add(removeLabel);

            buttonPanel.addStyleName("bonita_upload_button_group");

            loadingImage.setVisible(false);
            if (value != null && isInitialContentFile) {
                fileDownloadWidget.setFileName(value);
                formPanel.setVisible(false);
            } else {
                fileDownloadWidget.setVisible(false);
                modifyLabel.setVisible(false);
                removeLabel.setVisible(false);
            }
            cancelLabel.setVisible(false);

            filePanel.add(formPanel);
            filePanel.add(loadingImage);
            filePanel.add(fileDownloadWidget);
            filePanel.add(buttonPanel);
            modifyLabel.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(final ClickEvent event) {
                    formPanel.setVisible(true);
                    fileDownloadWidget.setVisible(false);
                    modifyLabel.setVisible(false);
                    removeLabel.setVisible(false);
                    cancelLabel.setVisible(true);
                }
            });

            removeLabel.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(final ClickEvent event) {
                    formPanel.clear();
                    uploadedFilePath = null;
                    fileUpload = addFileUploalToFormPanel(fileUploadFormName);
                    formPanel.setVisible(true);
                    fileDownloadWidget.setVisible(false);
                    fileDownloadWidget.resetDownloadlink();
                    modifyLabel.setVisible(false);
                    removeLabel.setVisible(false);
                    cancelLabel.setVisible(false);
                }
            });

            cancelLabel.addClickHandler(new ClickHandler() {

                @Override
                public void onClick(final ClickEvent event) {
                    formPanel.setVisible(false);
                    fileDownloadWidget.setVisible(true);
                    modifyLabel.setVisible(true);
                    removeLabel.setVisible(true);
                    cancelLabel.setVisible(false);
                }
            });
            flowPanel.add(filePanel);
        }

        if (!FileWidgetInputType.FILE.equals(fileWidgetInputType)) {
            urlTextBox = new TextBox();
            if (value != null && !isInitialContentFile) {
                urlTextBox.setValue(value);
            }
            flowPanel.add(urlTextBox);
        }

        if (radioButtonGroupWidget != null) {
            if (FILE_DOCUMENT_TYPE.equals(radioButtonGroupWidget.getValue())) {
                urlTextBox.setVisible(false);
                filePanel.setVisible(true);
            } else {
                filePanel.setVisible(false);
                urlTextBox.setVisible(true);
            }
        }
    }

    protected boolean isValidInputType(final FileWidgetInputType fileWidgetInputType, final String value) {
        if (value != null) {
            if (FileWidgetInputType.URL.equals(fileWidgetInputType) && isInitialContentFile) {
                displayErrorMessage(FormsResourceBundle.getErrors().wrongContentOfTypeFileError());
                return false;
            } else if (FileWidgetInputType.FILE.equals(fileWidgetInputType) && !isInitialContentFile) {
                displayErrorMessage(FormsResourceBundle.getErrors().wrongContentOfTypeURLError());
                return false;
            }
        }
        return true;
    }

    protected void displayErrorMessage(final String message) {
        final Label errorMessage = new Label(message);
        errorMessage.addStyleName("callout-danger callout");
        flowPanel.add(errorMessage);
    }

    protected void createFileUploadForm(final String FileUloadName) {

        formPanel = new FormPanel();
        formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
        formPanel.setMethod(FormPanel.METHOD_POST);
        FormElement.as(formPanel.getElement()).setAcceptCharset("UTF-8");
        formPanel.setAction(RpcFormsServices.getFileUploadURL());
        fileUpload = addFileUploalToFormPanel(FileUloadName);
    }

    protected FileUpload addFileUploalToFormPanel(final String fileUploadName) {

        final FileUpload fileUpload = new FileUpload();
        fileUpload.addChangeHandler(new ChangeHandler() {

            @Override
            public void onChange(final ChangeEvent event) {
                formPanel.submit();
            }
        });
        fileUpload.setStyleName("bonita_file_upload");
        // mandatory because we are in a true form with a post action
        fileUpload.setName(fileUploadName);
        if (DOMUtils.getInstance().isIE8()) {
            fileUpload.getElement().setPropertyString("contentEditable", "false");
        }
        formPanel.add(fileUpload);
        final UploadSubmitHandler uploadHandler = new UploadSubmitHandler();
        formPanel.addSubmitHandler(uploadHandler);
        formPanel.addSubmitCompleteHandler(uploadHandler);

        return fileUpload;
    }

    protected class UploadSubmitHandler implements SubmitHandler, SubmitCompleteHandler {

        protected String filePath;

        /**
         * {@inheritDoc}
         */
        @Override
        public void onSubmit(final SubmitEvent event) {
            filePath = fileUpload.getFilename();
            if (filePath == null || filePath.length() == 0) {
                event.cancel();
            } else {
                formPanel.setVisible(false);
                loadingImage.setVisible(true);
            }
        }

        /**
         * {@inheritDoc}
         */
        @Override
        public void onSubmitComplete(final SubmitCompleteEvent event) {
            String response = getPlainTextResult(event);
            response = URL.decodeQueryString(response);
            response = response.replaceAll("&amp;", "&");
            response = response.replaceAll("&lt;", "<");
            response = response.replaceAll("&gt;", ">");
            uploadedFilePath = response;
            String realFileName = null;
            if (filePath.contains("\\")) {
                realFileName = filePath.substring(filePath.lastIndexOf("\\") + 1);
            } else if (filePath.contains("/")) {
                realFileName = filePath.substring(filePath.lastIndexOf("/") + 1);
            } else {
                realFileName = filePath;
            }
            final int divIndex = realFileName.indexOf("<div");
            if (divIndex > 0) {
                realFileName = realFileName.substring(0, divIndex);
            }
            loadingImage.setVisible(false);
            fileDownloadWidget.setFilePath(uploadedFilePath, realFileName);
            fileDownloadWidget.setVisible(true);
            modifyLabel.setVisible(true);
            removeLabel.setVisible(true);
            cancelLabel.setVisible(false);
        }

        /**
         * See BS-9072 - To avoid xss attack we return text/plain output in fileuploadservlet.
         * But GWT is converting plain text in html element (pre).
         * Need to do this hack to get real servlet response
         */
        private String getPlainTextResult(final SubmitCompleteEvent event) {
            final Element label = DOM.createLabel();
            label.setInnerHTML(event.getResults());
            return label.getInnerText();
        }
    }

    /**
     * @return the path to the uploaded file
     */
    public String getValue() {
        if (FileWidgetInputType.ALL.equals(fileWidgetInputType)) {
            if (FILE_DOCUMENT_TYPE.equals(radioButtonGroupWidget.getValue())) {
                return uploadedFilePath;
            } else {
                return urlTextBox.getValue();
            }
        } else if (FileWidgetInputType.FILE.equals(fileWidgetInputType)) {
            return uploadedFilePath;
        } else {
            return urlTextBox.getValue();
        }
    }

    /**
     * @return the type of the field value
     */
    public String getValueType() {
        if (FileWidgetInputType.ALL.equals(fileWidgetInputType)) {
            if (FILE_DOCUMENT_TYPE.equals(radioButtonGroupWidget.getValue())) {
                return SupportedFieldTypes.JAVA_FILE_CLASSNAME;
            } else {
                return SupportedFieldTypes.JAVA_STRING_CLASSNAME;
            }
        } else if (FileWidgetInputType.FILE.equals(fileWidgetInputType)) {
            return SupportedFieldTypes.JAVA_FILE_CLASSNAME;
        } else {
            return SupportedFieldTypes.JAVA_STRING_CLASSNAME;
        }
    }

    /**
     * Disable the fileupload
     */
    public void disable() {
        filePanel.remove(formPanel);
        filePanel.remove(buttonPanel);
        fileDownloadWidget.setVisible(true);
    }

    @Override
    public void onValueChange(final ValueChangeEvent<Boolean> event) {
        if (FILE_DOCUMENT_TYPE.equals(radioButtonGroupWidget.getValue())) {
            urlTextBox.setVisible(false);
            filePanel.setVisible(true);
        } else {
            filePanel.setVisible(false);
            urlTextBox.setVisible(true);
        }
    }

    public String getAttachmentName() {
        return attachmentName;
    }

    public long getAttachmentId() {
        return attachmentId;
    }

    public String getDisplayedValue() {
        String displayedValue = null;
        if (FileWidgetInputType.ALL.equals(fileWidgetInputType)) {
            if (FILE_DOCUMENT_TYPE.equals(radioButtonGroupWidget.getValue())) {
                displayedValue = fileDownloadWidget.getDisplayedValue();
            } else {
                displayedValue = urlTextBox.getValue();
            }
        } else if (FileWidgetInputType.FILE.equals(fileWidgetInputType)) {
            displayedValue = fileDownloadWidget.getDisplayedValue();
        } else {
            displayedValue = urlTextBox.getValue();
        }
        return displayedValue;
    }
}