/*
* Copyright (C) 2012 Jan Pokorsky
*
* 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 3 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 cz.cas.lib.proarc.webapp.client.widget;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.RecordList;
import com.smartgwt.client.types.Alignment;
import com.smartgwt.client.types.SelectionStyle;
import com.smartgwt.client.types.SortDirection;
import com.smartgwt.client.types.TextAreaWrap;
import com.smartgwt.client.util.BooleanCallback;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.fields.MiniDateRangeItem;
import com.smartgwt.client.widgets.form.fields.SelectItem;
import com.smartgwt.client.widgets.form.fields.TextAreaItem;
import com.smartgwt.client.widgets.form.fields.TextItem;
import com.smartgwt.client.widgets.grid.ListGrid;
import com.smartgwt.client.widgets.grid.ListGridField;
import com.smartgwt.client.widgets.grid.events.CellDoubleClickEvent;
import com.smartgwt.client.widgets.grid.events.CellDoubleClickHandler;
import com.smartgwt.client.widgets.grid.events.DataArrivedEvent;
import com.smartgwt.client.widgets.grid.events.DataArrivedHandler;
import com.smartgwt.client.widgets.grid.events.SelectionUpdatedEvent;
import com.smartgwt.client.widgets.grid.events.SelectionUpdatedHandler;
import com.smartgwt.client.widgets.layout.VLayout;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import cz.cas.lib.proarc.common.object.model.DatastreamEditorType;
import cz.cas.lib.proarc.webapp.client.ClientMessages;
import cz.cas.lib.proarc.webapp.client.ClientUtils;
import cz.cas.lib.proarc.webapp.client.Editor;
import cz.cas.lib.proarc.webapp.client.action.AbstractAction;
import cz.cas.lib.proarc.webapp.client.action.Action;
import cz.cas.lib.proarc.webapp.client.action.ActionEvent;
import cz.cas.lib.proarc.webapp.client.action.Actions;
import cz.cas.lib.proarc.webapp.client.action.Actions.ActionSource;
import cz.cas.lib.proarc.webapp.client.action.RefreshAction;
import cz.cas.lib.proarc.webapp.client.action.RefreshAction.Refreshable;
import cz.cas.lib.proarc.webapp.client.ds.ImportBatchDataSource;
import cz.cas.lib.proarc.webapp.client.ds.ImportBatchDataSource.BatchRecord;
import cz.cas.lib.proarc.webapp.client.presenter.DigitalObjectEditing.DigitalObjectEditorPlace;
import cz.cas.lib.proarc.webapp.client.widget.Dialog.DialogCloseHandler;
import cz.cas.lib.proarc.webapp.shared.rest.ConfigurationProfileResourceApi.ProfileGroup;
/**
* The widget to select a batch from import history. There should be 2 kinds of
* batch items. The imported and not yet imported batches. The second one can be
* resumed.
*
* @author Jan Pokorsky
*/
public final class ImportBatchChooser extends VLayout implements Refreshable {
private ImportBatchChooserHandler handler;
private final ListGrid lGridBatches;
private final DynamicForm logForm;
private final ClientMessages i18n;
private final ActionSource actionSource;
private Action resumeAction;
private BatchRecord lastSelection;
private String lastProfileSelection;
public ImportBatchChooser(ClientMessages i18n) {
this.i18n = i18n;
this.actionSource = new ActionSource(this);
setWidth100();
setHeight100();
lGridBatches = initBatchesListGrid();
lGridBatches.setDataSource(ImportBatchDataSource.getInstance());
lGridBatches.setShowResizeBar(true);
lGridBatches.setResizeBarTarget("next");
ToolStrip toolbar = createToolbar();
logForm = createLogForm();
VLayout innerLayout = new VLayout();
innerLayout.setMargin(4);
innerLayout.addMember(lGridBatches);
innerLayout.addMember(logForm);
setMembers(toolbar, innerLayout);
}
private ListGrid initBatchesListGrid() {
ListGrid lg = new ListGrid();
lg.setHeight100();
lg.setSelectionType(SelectionStyle.SINGLE);
lg.setCanReorderFields(false);
lg.setShowFilterEditor(true);
lg.setAllowFilterOperators(false);
lg.setFilterOnKeypress(true);
lg.setGenerateDoubleClickOnEnter(true);
ListGridField lgfFolder = new ListGridField(ImportBatchDataSource.FIELD_DESCRIPTION,
i18n.ImportBatchDataSource_FolderFieldTitle());
// lgfFolder.setAutoFitWidth(false);
lgfFolder.setCanFilter(true);
lgfFolder.setFilterOnKeypress(false);
TextItem lgfFolderFilter = new TextItem();
lgfFolderFilter.setPrompt(i18n.ImportBatchChooser_FilterFolder_Hint());
lgfFolderFilter.setHoverWidth(200);
lgfFolder.setFilterEditorProperties(lgfFolderFilter);
lgfFolder.setCanSort(false);
ListGridField lgfDate = new ListGridField(ImportBatchDataSource.FIELD_CREATE,
i18n.ImportBatchDataSource_ImportDateFieldTitle());
lgfDate.setWidth(120);
lgfDate.setAlign(Alignment.CENTER);
lgfDate.setCanSort(true);
MiniDateRangeItem dateRangeItem = new MiniDateRangeItem();
dateRangeItem.setAttribute("allowRelativeDates", false);
lgfDate.setFilterEditorProperties(dateRangeItem);
lgfDate.setCanFilter(true);
ListGridField lgfModified = new ListGridField(ImportBatchDataSource.FIELD_TIMESTAMP,
i18n.ImportBatchDataSource_ImportModifiedFieldTitle());
lgfModified.setWidth(120);
lgfModified.setAlign(Alignment.CENTER);
lgfModified.setCanSort(true);
MiniDateRangeItem modifiedRangeItem = new MiniDateRangeItem();
modifiedRangeItem.setAttribute("allowRelativeDates", false);
lgfModified.setFilterEditorProperties(modifiedRangeItem);
lgfModified.setCanFilter(true);
ListGridField lgfImported = new ListGridField(ImportBatchDataSource.FIELD_STATE,
i18n.ImportBatchDataSource_StateFieldTitle());
lgfImported.setWidth(150);
lgfImported.setPrompt(ClientUtils.format("<div style='width:250px;'>%s</div>",
i18n.ImportBatchDataSource_StateFieldHint()));
lgfImported.setCanFilter(true);
lgfImported.setCanSort(true);
ListGridField lgfUser = new ListGridField(ImportBatchDataSource.FIELD_USER_DISPLAYNAME,
i18n.ImportBatchDataSource_UserFieldTitle());
lgfUser.setWidth(150);
lgfUser.setCanFilter(false);
lgfUser.setCanSort(false);
lg.setFields(lgfFolder, lgfDate, lgfModified, lgfImported, lgfUser);
lg.addSelectionUpdatedHandler(new SelectionUpdatedHandler() {
@Override
public void onSelectionUpdated(SelectionUpdatedEvent event) {
updateOnSelection();
}
});
Criteria filter = new Criteria();
filter.addCriteria(lgfImported.getName(), ImportBatchDataSource.State.LOADED.toString());
lg.setInitialCriteria(filter);
lg.setSortField(lgfModified.getName());
lg.setSortDirection(SortDirection.DESCENDING);
lg.addDataArrivedHandler(new DataArrivedHandler() {
@Override
public void onDataArrived(DataArrivedEvent event) {
int startRow = event.getStartRow();
if (startRow == 0) {
int select = 0;
if (lastSelection != null) {
RecordList rl = lGridBatches.getResultSet();
int findIndex = rl.findIndex(ImportBatchDataSource.FIELD_ID, lastSelection.getId());
select = findIndex < 0 ? select : findIndex;
}
lGridBatches.selectSingleRecord(select);
lGridBatches.scrollToRow(select);
lGridBatches.focus();
}
}
});
lg.addCellDoubleClickHandler(new CellDoubleClickHandler() {
@Override
public void onCellDoubleClick(CellDoubleClickEvent event) {
ActionEvent evt = new ActionEvent(actionSource.getSource());
if (resumeAction.accept(evt)) {
resumeAction.performAction(evt);
}
}
});
return lg;
}
@Override
public void refresh() {
bind();
}
public void bind() {
lastProfileSelection = null;
lGridBatches.invalidateCache();
lGridBatches.fetchData(lGridBatches.getCriteria());
}
public void setHandler(ImportBatchChooserHandler handler) {
this.handler = handler;
}
public BatchRecord getSelectedBatch() {
Record r = getSelectedRecord();
return r == null ? null : new BatchRecord(r);
}
/**
* A configuration profile as a parameter to reset the batch.
* @return the profile
* @see #getSelectedBatch()
*/
public String getSelectedProfile() {
return lastProfileSelection;
}
public Record getSelectedRecord() {
return lGridBatches.getSelectedRecord();
}
private void showLog(BatchRecord batch) {
if (batch != null) {
logForm.editRecord(batch.getDelegate());
String log = batch.getLog();
logForm.setVisible(log != null && !log.isEmpty());
} else {
logForm.clearValues();
logForm.hide();
}
}
private void updateOnSelection() {
actionSource.fireEvent();
BatchRecord r = getSelectedBatch();
lastSelection = r;
showLog(r);
}
private ToolStrip createToolbar() {
RefreshAction refreshAction = new RefreshAction(i18n);
resumeAction = new ResumeAction(i18n.ImportBatchChooser_ActionResume_Title(),
"[SKIN]/actions/next.png", i18n.ImportBatchChooser_ActionResume_Hint());
Action resetAction = new ResetImportAction(i18n.ImportBatchChooser_ActionResetLoad_Title(),
"[SKIN]/actions/undo.png",
i18n.ImportBatchChooser_ActionResetLoad_Hint());
Action parentAction = new ParentAction(i18n.ImportBatchChooser_ActionGotoParent_Title(),
"[SKIN]/actions/edit.png",
i18n.ImportBatchChooser_ActionGotoParent_Hint());
ToolStrip t = Actions.createToolStrip();
t.addMember(Actions.asIconButton(refreshAction, this));
t.addMember(Actions.asIconButton(resetAction, actionSource));
t.addMember(Actions.asIconButton(parentAction, actionSource));
t.addMember(Actions.asIconButton(resumeAction, actionSource));
return t;
}
private void resetImportFolder(final BatchRecord batch) {
ImportBatchDataSource.State state = batch.getState();
final BooleanCallback callback = new BooleanCallback() {
@Override
public void execute(Boolean value) {
if (value != null && value) {
handler.itemReset();
}
}
};
if (state == ImportBatchDataSource.State.INGESTING_FAILED) {
callback.execute(true);
} else {
askForBatchReload(callback, batch);
}
}
private void askForBatchReload(final BooleanCallback callback, BatchRecord batch) {
final Dialog dialog = new Dialog(i18n.ImportBatchChooser_ActionResetLoad_Title());
dialog.getDialogLabelContainer().setContents(i18n.ImportBatchChooser_ActionResetLoad_Ask_MSg());
final DynamicForm dialogForm = new DynamicForm();
final SelectItem profileSelect = ProfileChooser.createProfileSelection(ProfileGroup.IMPORTS, i18n);
profileSelect.setValue(batch.getProfileId());
dialogForm.setFields(profileSelect);
dialog.getDialogContentContainer().setMembers(dialogForm);
dialog.addYesButton(new com.smartgwt.client.widgets.events.ClickHandler() {
@Override
public void onClick(com.smartgwt.client.widgets.events.ClickEvent event) {
if (dialogForm.validate()) {
lastProfileSelection = profileSelect.getValueAsString();
dialog.destroy();
callback.execute(true);
}
}
});
dialog.addNoButton(new DialogCloseHandler() {
@Override
public void onClose() {
dialog.destroy();
lastProfileSelection = null;
callback.execute(false);
}
});
dialog.setWidth(400);
dialog.show();
}
private DynamicForm createLogForm() {
DynamicForm form = new DynamicForm();
form.setBrowserSpellCheck(false);
form.setCanEdit(false);
form.setWidth100();
form.setHeight("40%");
TextAreaItem textAreaItem = new TextAreaItem(ImportBatchDataSource.FIELD_LOG);
textAreaItem.setColSpan("*");
textAreaItem.setHeight("*");
textAreaItem.setWrap(TextAreaWrap.OFF);
textAreaItem.setShowTitle(false);
textAreaItem.setWidth("*");
textAreaItem.setCanEdit(false);
form.setItems(textAreaItem);
return form;
}
public interface ImportBatchChooserHandler {
void itemSelected();
void itemReset();
}
/**
* Opens a loaded import.
*/
private final class ResumeAction extends AbstractAction {
public ResumeAction(String title, String icon, String tooltip) {
super(title, icon, tooltip);
}
@Override
public void performAction(ActionEvent event) {
handler.itemSelected();
}
@Override
public boolean accept(ActionEvent event) {
BatchRecord record = getSelectedBatch();
if (record != null && !record.isArchive()) {
return record.getState() == ImportBatchDataSource.State.LOADED;
}
return false;
}
}
/**
* Resets a failed import.
*/
private final class ResetImportAction extends AbstractAction {
public ResetImportAction(String title, String icon, String tooltip) {
super(title, icon, tooltip);
}
@Override
public void performAction(ActionEvent event) {
BatchRecord record = getSelectedBatch();
if (record != null) {
resetImportFolder(record);
}
}
@Override
public boolean accept(ActionEvent event) {
BatchRecord record = getSelectedBatch();
boolean accept = false;
if (record != null) {
switch(record.getState()) {
case INGESTING_FAILED:
setTitle(i18n.ImportBatchChooser_ActionResetIngest_Title());
setTooltip(i18n.ImportBatchChooser_ActionResetIngest_Hint());
accept = true;
break;
case LOADING_FAILED:
case LOADED:
setTitle(i18n.ImportBatchChooser_ActionResetLoad_Title());
setTooltip(i18n.ImportBatchChooser_ActionResetLoad_Hint());
accept = true;
break;
}
}
return accept;
}
}
/** Opens a selected parent object. */
private final class ParentAction extends AbstractAction {
public ParentAction(String title, String icon, String tooltip) {
super(title, icon, tooltip);
}
@Override
public boolean accept(ActionEvent event) {
BatchRecord batch = getSelectedBatch();
return batch != null && batch.getParentPid() != null && !batch.isArchive();
}
@Override
public void performAction(ActionEvent event) {
BatchRecord batch = getSelectedBatch();
if (batch != null && batch.getParentPid() != null) {
Editor.getInstance().getEditorWorkFlow().getPlaceController()
.goTo(new DigitalObjectEditorPlace(DatastreamEditorType.CHILDREN, batch.getParentPid()));
}
}
}
}