/*
* FileUploadDialog.java
*
* Copyright (C) 2009-12 by RStudio, Inc.
*
* Unless you have received this program directly from RStudio pursuant
* to the terms of a commercial license agreement with RStudio, then
* this program is licensed to you under the terms of version 3 of the
* GNU Affero General Public License. This program is distributed WITHOUT
* ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
* MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
* AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
*
*/
package org.rstudio.studio.client.workbench.views.files.ui;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.*;
import org.rstudio.core.client.files.FileSystemItem;
import org.rstudio.core.client.files.filedialog.FileDialogResources;
import org.rstudio.core.client.jsonrpc.RpcError;
import org.rstudio.core.client.jsonrpc.RpcResponse;
import org.rstudio.core.client.theme.res.ThemeStyles;
import org.rstudio.core.client.widget.HtmlFormModalDialog;
import org.rstudio.core.client.widget.OperationWithInput;
import org.rstudio.core.client.widget.ProgressIndicator;
import org.rstudio.core.client.widget.ProgressOperationWithInput;
import org.rstudio.studio.client.common.FileDialogs;
import org.rstudio.studio.client.common.filetypes.FileIconResources;
import org.rstudio.studio.client.workbench.model.RemoteFileSystemContext;
import org.rstudio.studio.client.workbench.views.files.model.PendingFileUpload;
public class FileUploadDialog extends HtmlFormModalDialog<PendingFileUpload>
{
public FileUploadDialog(
String actionURL,
FileSystemItem targetDirectory,
FileDialogs fileDialogs,
RemoteFileSystemContext fileSystemContext,
OperationWithInput<PendingFileUpload> completedOperation)
{
super("Upload Files",
"Uploading file...",
actionURL,
completedOperation);
fileDialogs_ = fileDialogs;
fileSystemContext_ = fileSystemContext;
targetDirectory_ = targetDirectory;
}
@Override
protected void positionAndShowDialog(final Command onCompleted)
{
final PopupPanel thisPanel = this;
setPopupPositionAndShow(new PopupPanel.PositionCallback() {
public void setPosition(int offsetWidth, int offsetHeight)
{
int left = (Window.getClientWidth()/2) - (offsetWidth/2);
int top = (Window.getClientHeight()/2) - (offsetHeight/2);
// clip the top so the choose file dialog always appears
// over the file upload dialog (mostly a problem on osx)
top = Math.min(top, 200);
thisPanel.setPopupPosition(left, top);
onCompleted.execute();
}
});
}
@Override
protected void setFormPanelEncodingAndMethod(FormPanel formPanel)
{
formPanel.setEncoding(FormPanel.ENCODING_MULTIPART);
formPanel.setMethod(FormPanel.METHOD_POST);
}
@Override
protected PendingFileUpload parseResults(String results) throws Exception
{
RpcResponse response = RpcResponse.parse(results);
if (response == null)
throw new Exception("Unexpected response from server");
// check for errors
RpcError error = response.getError();
if (error != null)
{
// special error message if we know the user failed to
// select a directory
if (error.getCode() == RpcError.PARAM_INVALID &&
fileUpload_.getFilename().length() == 0)
{
throw new Exception("You must specify a file to upload.");
}
else
{
throw new Exception(error.getEndUserMessage());
}
}
// return PendingFileUpload
PendingFileUpload pendingFileUpload = response.getResult();
return pendingFileUpload;
}
// NOTE: discovered that GWT was always submitting the form whether
// or not we cancelled the SubmitEvent. Perhaps their bug? Anyway, the
// solution was to always return true for validation and then to check
// for the empty fileUpload filename above in parseResults (knowing that
// the server would always return an error if no file was specified)
@Override
protected boolean validate()
{
return true;
}
@Override
protected Widget createMainWidget()
{
VerticalPanel panel = new VerticalPanel();
panel.setStyleName(ThemeStyles.INSTANCE.fileUploadPanel());
// directory panel
HorizontalPanel directoryPanel = new HorizontalPanel();
directoryPanel.setWidth("100%");
directoryPanel.setStyleName(ThemeStyles.INSTANCE.fileUploadField());
// directory name (informational field)
panel.add(new Label("Target directory:"));
directoryNameWidget_ = new DirectoryNameWidget();
directoryNameWidget_.setDirectory(targetDirectory_);
directoryPanel.add(directoryNameWidget_);
// browse directory button
// JJA: removed browse button (was causing confusion for users who
// thought it was what they should press to browse local files)
/*
Button browseButton = new Button("Browse...",
new BrowseDirectoryClickHandler());
browseButton.getElement().getStyle().setMarginRight(5, Unit.PX);
directoryPanel.add(browseButton);
directoryPanel.setCellHorizontalAlignment(
browseButton,
HasHorizontalAlignment.ALIGN_RIGHT);
*/
panel.add(directoryPanel);
// filename field
panel.add(new Label("File to upload:"));
fileUpload_ = new FileUpload();
fileUpload_.setStyleName(ThemeStyles.INSTANCE.fileUploadField());
fileUpload_.setName("file");
panel.add(fileUpload_);
// zip file tip field
HTML tip = new HTML("<b>TIP</b>: To upload multiple files or a " +
"directory, create a zip file. The zip file will " +
"be automatically expanded after upload.");
tip.addStyleName(ThemeStyles.INSTANCE.fileUploadField());
tip.addStyleName(ThemeStyles.INSTANCE.fileUploadTipLabel());
panel.add(tip);
// target directory hidden field
targetDirectoryHidden_ = new Hidden("targetDirectory",
targetDirectory_.getPath());
panel.add(targetDirectoryHidden_);
return panel;
}
// JJA: used by currently commented out browse directory button
@SuppressWarnings("unused")
private class BrowseDirectoryClickHandler implements ClickHandler
{
public void onClick(ClickEvent event)
{
fileDialogs_.chooseFolder(
"Choose Target Directory",
fileSystemContext_,
targetDirectory_,
new ProgressOperationWithInput<FileSystemItem>() {
public void execute(FileSystemItem input,
ProgressIndicator indicator)
{
if (input == null)
return;
indicator.onCompleted();
targetDirectory_ = input;
targetDirectoryHidden_.setValue(input.getPath());
directoryNameWidget_.setDirectory(input);
}
});
}
}
private class DirectoryNameWidget extends HorizontalPanel
{
public DirectoryNameWidget()
{
setHorizontalAlignment(HasHorizontalAlignment.ALIGN_LEFT);
image_ = new Image();
image_.setStyleName(
FileDialogResources.INSTANCE.styles().columnIcon());
this.add(image_);
name_ = new HTML();
this.add(name_);
}
public void setDirectory(FileSystemItem directoryItem)
{
if (directoryItem.equalTo(FileSystemItem.home()))
{
image_.setResource(FileDialogResources.INSTANCE.homeImage());
name_.setHTML("Home");
}
else
{
image_.setResource(FileIconResources.INSTANCE.iconFolder());
name_.setHTML(" " + directoryItem.getPath());
}
}
Image image_ ;
HTML name_ ;
}
private FileUpload fileUpload_;
private FileSystemItem targetDirectory_;
private Hidden targetDirectoryHidden_;
private DirectoryNameWidget directoryNameWidget_;
private final FileDialogs fileDialogs_;
private RemoteFileSystemContext fileSystemContext_;
}