com.google.appinventor.client.wizards.FileUploadWizard.java Source code

Java tutorial

Introduction

Here is the source code for com.google.appinventor.client.wizards.FileUploadWizard.java

Source

// -*- mode: java; c-basic-offset: 2; -*-
// Copyright 2009-2011 Google, All Rights reserved
// Copyright 2011-2012 MIT, All rights reserved
// Released under the Apache License, Version 2.0
// http://www.apache.org/licenses/LICENSE-2.0

package com.google.appinventor.client.wizards;

import static com.google.appinventor.client.Ode.MESSAGES;

import java.io.File;

import com.google.appinventor.client.ErrorReporter;
import com.google.appinventor.client.Ode;
import com.google.appinventor.client.OdeAsyncCallback;
import com.google.appinventor.client.explorer.project.Project;
import com.google.appinventor.client.utils.Uploader;
import com.google.appinventor.client.youngandroid.TextValidators;
import com.google.appinventor.shared.rpc.ServerLayout;
import com.google.appinventor.shared.rpc.UploadResponse;
import com.google.appinventor.shared.rpc.project.FileNode;
import com.google.appinventor.shared.rpc.project.FolderNode;
import com.google.appinventor.shared.rpc.project.ProjectNode;
import com.google.appinventor.shared.rpc.project.youngandroid.YoungAndroidAssetNode;
import com.google.appinventor.shared.rpc.project.youngandroid.YoungAndroidAssetsFolder;
import com.google.gwt.core.client.GWT;
import com.google.gwt.http.client.URL;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.FileUpload;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Anchor;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;

/**
 * Wizard for uploading individual files.
 *
 */
public class FileUploadWizard extends Wizard {
    /**
     * Interface for callback to execute after a file is uploaded.
     */
    public static interface FileUploadedCallback {
        /**
         * Will be invoked after a file is uploaded.
         *
         * @param folderNode the upload destination folder
         * @param fileNode the file just uploaded
         */
        void onFileUploaded(FolderNode folderNode, FileNode fileNode);
    }

    /**
     * Creates a new file upload wizard.
     *
     * @param folderNode the upload destination folder
     */
    public FileUploadWizard(FolderNode folderNode) {
        this(folderNode, null);
    }

    /**
     * Creates a new file upload wizard.
     *
     * @param folderNode the upload destination folder
     * @param fileUploadedCallback callback to be executed after upload
     */
    public FileUploadWizard(final FolderNode folderNode, final FileUploadedCallback fileUploadedCallback) {
        super(MESSAGES.fileUploadWizardCaption(), true, false);

        // Initialize UI
        final FileUpload upload = new FileUpload();
        upload.setName(ServerLayout.UPLOAD_FILE_FORM_ELEMENT);
        setStylePrimaryName("ode-DialogBox");
        VerticalPanel panel = new VerticalPanel();
        panel.setVerticalAlignment(VerticalPanel.ALIGN_MIDDLE);
        panel.add(upload);
        addPage(panel);

        // Create finish command (upload a file)
        initFinishCommand(new Command() {
            @Override
            public void execute() {
                String uploadFilename = upload.getFilename();
                if (!uploadFilename.isEmpty()) {
                    final String filename = makeValidFilename(uploadFilename);
                    if (!TextValidators.isValidCharFilename(filename)) {
                        createErrorDialog(MESSAGES.malformedFilenameTitle(), MESSAGES.malformedFilename(),
                                Error.NOFILESELECETED, folderNode, fileUploadedCallback);
                        return;
                    } else if (!TextValidators.isValidLengthFilename(filename)) {
                        createErrorDialog(MESSAGES.filenameBadSizeTitle(), MESSAGES.filenameBadSize(),
                                Error.FILENAMEBADSIZE, folderNode, fileUploadedCallback);
                        return;
                    }
                    int nameLength = uploadFilename.length();
                    String fileEnd = uploadFilename.substring(nameLength - 4, nameLength);

                    if (".aia".equals(fileEnd.toLowerCase())) {
                        createErrorDialog(MESSAGES.aiaMediaAssetTitle(), MESSAGES.aiaMediaAsset(),
                                Error.AIAMEDIAASSET, folderNode, fileUploadedCallback);
                        return;
                    }
                    String fn = conflictingExistingFile(folderNode, filename);
                    if (fn != null && !confirmOverwrite(folderNode, fn, filename)) {
                        return;
                    } else {
                        String fileId = folderNode.getFileId() + "/" + filename;
                        // We delete all the conflicting files.
                        for (ProjectNode child : folderNode.getChildren()) {
                            if (fileId.equalsIgnoreCase(child.getFileId()) && !fileId.equals(child.getFileId())) {
                                final ProjectNode node = child;
                                String filesToClose[] = { node.getFileId() };
                                Ode ode = Ode.getInstance();
                                ode.getEditorManager().closeFileEditors(node.getProjectId(), filesToClose);
                                ode.getProjectService().deleteFile(ode.getSessionId(), node.getProjectId(),
                                        node.getFileId(), new OdeAsyncCallback<Long>(
                                                // message on failure
                                                MESSAGES.deleteFileError()) {
                                            @Override
                                            public void onSuccess(Long date) {
                                                Ode.getInstance().getProjectManager().getProject(node)
                                                        .deleteNode(node);
                                                Ode.getInstance().updateModificationDate(node.getProjectId(), date);

                                            }
                                        });
                            }
                        }
                    }
                    ErrorReporter.reportInfo(MESSAGES.fileUploadingMessage(filename));

                    // Use the folderNode's project id and file id in the upload URL so that the file is
                    // uploaded into that project and that folder in our back-end storage.
                    String uploadUrl = GWT.getModuleBaseURL() + ServerLayout.UPLOAD_SERVLET + "/"
                            + ServerLayout.UPLOAD_FILE + "/" + folderNode.getProjectId() + "/"
                            + folderNode.getFileId() + "/" + filename;
                    Uploader.getInstance().upload(upload, uploadUrl,
                            new OdeAsyncCallback<UploadResponse>(MESSAGES.fileUploadError()) {
                                @Override
                                public void onSuccess(UploadResponse uploadResponse) {
                                    switch (uploadResponse.getStatus()) {
                                    case SUCCESS:
                                        ErrorReporter.hide();
                                        onUploadSuccess(folderNode, filename, uploadResponse.getModificationDate(),
                                                fileUploadedCallback);
                                        break;
                                    case FILE_TOO_LARGE:
                                        // The user can resolve the problem by
                                        // uploading a smaller file.
                                        ErrorReporter.reportInfo(MESSAGES.fileTooLargeError());
                                        break;
                                    default:
                                        ErrorReporter.reportError(MESSAGES.fileUploadError());
                                        break;
                                    }
                                }
                            });
                } else {
                    createErrorDialog(MESSAGES.noFileSelectedTitle(), MESSAGES.noFileSelected(),
                            Error.NOFILESELECETED, folderNode, fileUploadedCallback);
                }
            }
        });
    }

    @Override
    public void show() {
        super.show();
        int width = 320;
        int height = 40;
        this.center();

        setPixelSize(width, height);
        super.setPagePanelHeight(40);
    }

    private String makeValidFilename(String uploadFilename) {
        // Strip leading path off filename.
        // We need to support both Unix ('/') and Windows ('\\') separators.
        String filename = uploadFilename
                .substring(Math.max(uploadFilename.lastIndexOf('/'), uploadFilename.lastIndexOf('\\')) + 1);
        // We need to strip out whitespace from the filename.
        filename = filename.replaceAll("\\s", "");
        return filename;
    }

    private String conflictingExistingFile(FolderNode folderNode, String filename) {
        String fileId = folderNode.getFileId() + "/" + filename;
        for (ProjectNode child : folderNode.getChildren()) {
            if (fileId.equalsIgnoreCase(child.getFileId())) {
                // we want to return kitty.png rather than assets/kitty.png
                return lastPathComponent(child.getFileId());
            }
        }
        return null;
    }

    private String lastPathComponent(String path) {
        String[] pieces = path.split("/");
        return pieces[pieces.length - 1];
    }

    private boolean confirmOverwrite(FolderNode folderNode, String newFile, String existingFile) {
        return Window.confirm(MESSAGES.confirmOverwrite(newFile, existingFile));
    }

    private void onUploadSuccess(final FolderNode folderNode, final String filename, long modificationDate,
            final FileUploadedCallback fileUploadedCallback) {
        Ode.getInstance().updateModificationDate(folderNode.getProjectId(), modificationDate);
        finishUpload(folderNode, filename, fileUploadedCallback);
    }

    private void finishUpload(FolderNode folderNode, String filename, FileUploadedCallback fileUploadedCallback) {
        String uploadedFileId = folderNode.getFileId() + "/" + filename;
        FileNode uploadedFileNode;
        if (folderNode instanceof YoungAndroidAssetsFolder) {
            uploadedFileNode = new YoungAndroidAssetNode(filename, uploadedFileId);
        } else {
            uploadedFileNode = new FileNode(filename, uploadedFileId);
        }

        Project project = Ode.getInstance().getProjectManager().getProject(folderNode);
        uploadedFileNode = (FileNode) project.addNode(folderNode, uploadedFileNode);

        if (fileUploadedCallback != null) {
            fileUploadedCallback.onFileUploaded(folderNode, uploadedFileNode);
        }
    }

    private void createErrorDialog(String title, String body, Error e, final FolderNode folderNode,
            final FileUploadedCallback fileUploadedCallback) {
        final DialogBox dialogBox = new DialogBox(false, true);
        HTML message;
        dialogBox.setStylePrimaryName("ode-DialogBox");
        dialogBox.setHeight("150px");
        dialogBox.setWidth("350px");
        dialogBox.setGlassEnabled(true);
        dialogBox.setAnimationEnabled(true);
        dialogBox.center();
        VerticalPanel DialogBoxContents = new VerticalPanel();
        FlowPanel holder = new FlowPanel();
        Button ok = new Button("OK");
        ok.addClickListener(new ClickListener() {
            public void onClick(Widget sender) {
                dialogBox.hide();
                new FileUploadWizard(folderNode, fileUploadedCallback).show();
            }
        });
        holder.add(ok);
        dialogBox.setText(title);
        message = new HTML(body);

        switch (e) {
        case AIAMEDIAASSET:
            Button info = new Button("More Info");
            info.addClickListener(new ClickListener() {
                public void onClick(Widget sender) {
                    Window.open(MESSAGES.aiaMediaAssetHelp(), "AIA Help", "");
                }
            });
            holder.add(info);
        case NOFILESELECETED:
        case MALFORMEDFILENAME:
        case FILENAMEBADSIZE:
        default:
            break;
        }

        message.setStyleName("DialogBox-message");
        DialogBoxContents.add(message);
        DialogBoxContents.add(holder);
        dialogBox.setWidget(DialogBoxContents);
        dialogBox.show();
    }

}

enum Error {
    AIAMEDIAASSET, NOFILESELECETED, MALFORMEDFILENAME, FILENAMEBADSIZE
}