/*
* UnsavedChangesDialog.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.ui.unsaved;
import java.util.ArrayList;
import org.rstudio.core.client.SafeHtmlUtil;
import org.rstudio.core.client.StringUtil;
import org.rstudio.core.client.widget.ModalDialog;
import org.rstudio.core.client.widget.Operation;
import org.rstudio.core.client.widget.OperationWithInput;
import org.rstudio.core.client.widget.ThemedButton;
import org.rstudio.studio.client.workbench.model.UnsavedChangesTarget;
import com.google.gwt.cell.client.AbstractCell;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.ImageResourceCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.resources.client.ClientBundle;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.resources.client.ImageResource;
import com.google.gwt.safehtml.shared.SafeHtmlBuilder;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.IdentityColumn;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.ui.CheckBox;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
public class UnsavedChangesDialog extends ModalDialog<UnsavedChangesDialog.Result>
{
public class Result
{
public Result(ArrayList<UnsavedChangesTarget> saveTargets,
boolean alwaysSave)
{
saveTargets_ = saveTargets;
alwaysSave_ = alwaysSave;
}
public ArrayList<UnsavedChangesTarget> getSaveTargets()
{
return saveTargets_;
}
public boolean getAlwaysSave()
{
return alwaysSave_;
}
private ArrayList<UnsavedChangesTarget> saveTargets_;
private boolean alwaysSave_;
}
public UnsavedChangesDialog(
String title,
ArrayList<UnsavedChangesTarget> dirtyTargets,
final OperationWithInput<Result> saveOperation,
final Command onCancelled)
{
this(title, null, dirtyTargets, saveOperation, onCancelled);
}
public UnsavedChangesDialog(
String title,
String alwaysSaveOption,
ArrayList<UnsavedChangesTarget> dirtyTargets,
final OperationWithInput<Result> saveOperation,
final Command onCancelled)
{
super(title,
saveOperation,
onCancelled != null ? new Operation() {
@Override
public void execute()
{
onCancelled.execute();
}} :
null);
alwaysSaveOption_ = StringUtil.notNull(alwaysSaveOption);
targets_ = dirtyTargets;
setOkButtonCaption("Save Selected");
addLeftButton(new ThemedButton("Don't Save", new ClickHandler() {
@Override
public void onClick(ClickEvent event)
{
closeDialog();
saveOperation.execute(new Result(
new ArrayList<UnsavedChangesTarget>(),
false));
}
}));
}
@Override
protected Widget createMainWidget()
{
// create cell table
targetsCellTable_ = new CellTable<UnsavedChangesTarget>(
15,
UnsavedChangesCellTableResources.INSTANCE,
KEY_PROVIDER);
selectionModel_ = new MultiSelectionModel<UnsavedChangesTarget>(KEY_PROVIDER);
targetsCellTable_.setSelectionModel(
selectionModel_,
DefaultSelectionEventManager.<UnsavedChangesTarget> createCheckboxManager());
targetsCellTable_.setWidth("100%", true);
// add columns
addSelectionColumn();
addIconColumn();
addNameAndPathColumn();
// hook-up data provider
dataProvider_ = new ListDataProvider<UnsavedChangesTarget>();
dataProvider_.setList(targets_);
dataProvider_.addDataDisplay(targetsCellTable_);
targetsCellTable_.setPageSize(targets_.size());
// select all by default
for (UnsavedChangesTarget editingTarget : dataProvider_.getList())
selectionModel_.setSelected(editingTarget, true);
// enclose cell table in scroll panel
ScrollPanel scrollPanel = new ScrollPanel();
scrollPanel.setStylePrimaryName(RESOURCES.styles().targetScrollPanel());
scrollPanel.setWidget(targetsCellTable_);
if (dataProvider_.getList().size() > 4)
scrollPanel.setHeight("280px");
// always save check box (may not be shown)
chkAlwaysSave_ = new CheckBox(alwaysSaveOption_);
// main widget
VerticalPanel panel = new VerticalPanel();
Label captionLabel = new Label(
"The following files have unsaved changes:");
captionLabel.setStylePrimaryName(RESOURCES.styles().captionLabel());
panel.add(captionLabel);
panel.add(scrollPanel);
if (!StringUtil.isNullOrEmpty(alwaysSaveOption_))
{
panel.add(chkAlwaysSave_);
panel.setCellHeight(chkAlwaysSave_, "30px");
panel.setCellVerticalAlignment(chkAlwaysSave_,
HasVerticalAlignment.ALIGN_MIDDLE);
}
return panel;
}
private Column<UnsavedChangesTarget, Boolean> addSelectionColumn()
{
Column<UnsavedChangesTarget, Boolean> checkColumn =
new Column<UnsavedChangesTarget, Boolean>(new CheckboxCell(true, false))
{
@Override
public Boolean getValue(UnsavedChangesTarget object)
{
return selectionModel_.isSelected(object);
}
};
checkColumn.setVerticalAlignment(HasVerticalAlignment.ALIGN_TOP);
targetsCellTable_.addColumn(checkColumn);
targetsCellTable_.setColumnWidth(checkColumn, 25, Unit.PX);
return checkColumn;
}
private Column<UnsavedChangesTarget, ImageResource> addIconColumn()
{
Column<UnsavedChangesTarget, ImageResource> iconColumn =
new Column<UnsavedChangesTarget, ImageResource>(new ImageResourceCell()) {
@Override
public ImageResource getValue(UnsavedChangesTarget object)
{
return object.getIcon();
}
};
targetsCellTable_.addColumn(iconColumn);
targetsCellTable_.setColumnWidth(iconColumn, 20, Unit.PX);
return iconColumn;
}
private class NameAndPathCell extends AbstractCell<UnsavedChangesTarget>
{
@Override
public void render(
com.google.gwt.cell.client.Cell.Context context,
UnsavedChangesTarget value, SafeHtmlBuilder sb)
{
if (value != null)
{
Styles styles = RESOURCES.styles();
String path = value.getPath();
if (path != null)
{
SafeHtmlUtil.appendDiv(sb, styles.targetName(), value.getTitle());
SafeHtmlUtil.appendDiv(sb, styles.targetPath(), path);
}
else
{
SafeHtmlUtil.appendDiv(sb,
styles.targetUntitled(),
value.getTitle());
}
}
}
}
private IdentityColumn<UnsavedChangesTarget> addNameAndPathColumn()
{
IdentityColumn<UnsavedChangesTarget> nameAndPathColumn =
new IdentityColumn<UnsavedChangesTarget>(new NameAndPathCell());
targetsCellTable_.addColumn(nameAndPathColumn);
targetsCellTable_.setColumnWidth(nameAndPathColumn, 350, Unit.PX);
return nameAndPathColumn;
}
@Override
protected Result collectInput()
{
return new Result(new ArrayList<UnsavedChangesTarget>(
selectionModel_.getSelectedSet()),
chkAlwaysSave_.getValue());
}
@Override
protected boolean validate(Result input)
{
return true;
}
static interface Styles extends CssResource
{
String targetScrollPanel();
String captionLabel();
String targetName();
String targetPath();
String targetUntitled();
}
static interface Resources extends ClientBundle
{
@Source("UnsavedChangesDialog.css")
Styles styles();
}
static Resources RESOURCES = (Resources) GWT.create(Resources.class);
public static void ensureStylesInjected()
{
RESOURCES.styles().ensureInjected();
}
private static final ProvidesKey<UnsavedChangesTarget> KEY_PROVIDER =
new ProvidesKey<UnsavedChangesTarget>() {
@Override
public Object getKey(UnsavedChangesTarget item)
{
return item.getId();
}
};
private final ArrayList<UnsavedChangesTarget> targets_;
private CellTable<UnsavedChangesTarget> targetsCellTable_;
private ListDataProvider<UnsavedChangesTarget> dataProvider_;
private MultiSelectionModel<UnsavedChangesTarget> selectionModel_;
private final String alwaysSaveOption_;
private CheckBox chkAlwaysSave_;
}