/*
* Copyright (C) 2015 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.workflow;
import com.google.gwt.user.client.ui.Widget;
import com.smartgwt.client.data.Criteria;
import com.smartgwt.client.data.DSCallback;
import com.smartgwt.client.data.DSRequest;
import com.smartgwt.client.data.DSResponse;
import com.smartgwt.client.data.Record;
import com.smartgwt.client.data.ResultSet;
import com.smartgwt.client.types.CriteriaPolicy;
import com.smartgwt.client.types.FetchMode;
import com.smartgwt.client.types.TitleOrientation;
import com.smartgwt.client.widgets.Canvas;
import com.smartgwt.client.widgets.form.DynamicForm;
import com.smartgwt.client.widgets.form.FormItemIfFunction;
import com.smartgwt.client.widgets.form.events.ItemChangedEvent;
import com.smartgwt.client.widgets.form.events.ItemChangedHandler;
import com.smartgwt.client.widgets.form.events.SubmitValuesEvent;
import com.smartgwt.client.widgets.form.events.SubmitValuesHandler;
import com.smartgwt.client.widgets.form.fields.FormItem;
import com.smartgwt.client.widgets.form.fields.FormItemIcon;
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.ListGridRecord;
import com.smartgwt.client.widgets.grid.events.RecordDoubleClickEvent;
import com.smartgwt.client.widgets.grid.events.RecordDoubleClickHandler;
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.menu.Menu;
import com.smartgwt.client.widgets.menu.MenuItem;
import com.smartgwt.client.widgets.menu.events.ItemClickEvent;
import com.smartgwt.client.widgets.menu.events.ItemClickHandler;
import com.smartgwt.client.widgets.toolbar.ToolStrip;
import cz.cas.lib.proarc.common.workflow.model.WorkflowModelConsts;
import cz.cas.lib.proarc.common.workflow.profile.WorkflowProfileConsts;
import cz.cas.lib.proarc.webapp.client.ClientMessages;
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.action.SaveAction;
import cz.cas.lib.proarc.webapp.client.ds.RestConfig;
import cz.cas.lib.proarc.webapp.client.ds.UserDataSource;
import cz.cas.lib.proarc.webapp.client.ds.WorkflowJobDataSource;
import cz.cas.lib.proarc.webapp.client.ds.WorkflowProfileDataSource;
import cz.cas.lib.proarc.webapp.client.ds.WorkflowTaskDataSource;
import cz.cas.lib.proarc.webapp.client.presenter.WorkflowJobsEditor;
import cz.cas.lib.proarc.webapp.client.widget.ListGridPersistance;
/**
*
* @author Jan Pokorsky
*/
public class WorkflowJobFormView implements Refreshable {
private final ClientMessages i18n;
private final Canvas widget;
private DynamicForm jobForm;
private WorkflowMaterialView materialView;
private ListGrid taskView;
private Menu addTaskMenu;
private WorkflowJobsEditor handler;
private Record lastJob;
private final ActionSource actionSource = new ActionSource(this);
private Action editTaskAction;
public WorkflowJobFormView(ClientMessages i18n) {
this.i18n = i18n;
this.widget = createMainLayout();
}
public Canvas getWidget() {
return widget;
}
public DynamicForm getJobValues() {
return jobForm;
}
public ListGrid getTasks() {
return taskView;
}
public void setHandler(WorkflowJobsEditor handler) {
this.handler = handler;
}
@Override
public void refresh() {
taskView.invalidateCache();
setJob(lastJob);
}
public void refreshState() {
actionSource.fireEvent();
}
public void setJob(final Record job) {
this.lastJob = job;
fetchAddTaskMenu(null);
if (job != null) {
String jobId = job.getAttribute(WorkflowJobDataSource.FIELD_ID);
jobForm.clearErrors(true);
jobForm.fetchData(new Criteria(WorkflowJobDataSource.FIELD_ID, jobId), new DSCallback() {
@Override
public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
refreshState();
}
});
taskView.fetchData(
new Criteria(WorkflowModelConsts.TASK_FILTER_JOBID, jobId),
new DSCallback() {
@Override
public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
if (RestConfig.isStatusOk(dsResponse)) {
Record[] records = dsResponse.getData();
if (records.length > 0) {
fetchAddTaskMenu(job.getAttribute(WorkflowJobDataSource.FIELD_PROFILE_ID));
}
}
}
});
materialView.setJobMaterials(jobId);
} else {
jobForm.clearValues();
materialView.setEmptyMaterials();
taskView.setData(new Record[0]);
}
widget.setDisabled(job == null);
refreshState();
}
private void fetchAddTaskMenu(final String jobName) {
addTaskMenu.setData(new Record[0]);
if (jobName == null) {
return ;
}
WorkflowProfileDataSource.getInstance().fetchData(
new Criteria(WorkflowProfileConsts.NAME, jobName),
new DSCallback() {
@Override
public void execute(DSResponse dsResponse, Object data, DSRequest dsRequest) {
Record[] taskRecs = new Record[0];
if (RestConfig.isStatusOk(dsResponse)) {
Record jobRec = dsResponse.getDataAsRecordList().find(WorkflowProfileConsts.NAME, jobName);
if (jobRec != null) {
taskRecs = jobRec.getAttributeAsRecordArray(WorkflowProfileConsts.JOBVIEW_TASK);
}
}
addTaskMenu.setData(taskRecs);
}
}, null);
}
private Canvas createMainLayout() {
VLayout main = new VLayout();
main.addMember(createJobToolbar());
main.addMember(createForm());
main.addMember(createTaskList());
main.addMember(createMaterialList());
return main;
}
private ToolStrip createJobToolbar() {
ToolStrip toolbar = Actions.createToolStrip();
RefreshAction refreshAction = new RefreshAction(i18n);
SaveAction saveAction = createSaveAction();
toolbar.addMember(Actions.asIconButton(refreshAction, this));
toolbar.addMember(Actions.asIconButton(saveAction, actionSource));
return toolbar;
}
private SaveAction createSaveAction() {
return new SaveAction(i18n) {
@Override
public boolean accept(ActionEvent event) {
return handler != null
&& jobForm.getValue(WorkflowJobDataSource.FIELD_ID) != null
&& getJobValues().valuesHaveChanged();
}
@Override
public void performAction(ActionEvent event) {
if (handler != null) {
handler.onSave(WorkflowJobFormView.this);
}
}
};
}
private Widget createForm() {
jobForm = new DynamicForm();
jobForm.setDataSource(WorkflowJobDataSource.getInstance());
jobForm.setNumCols(3);
jobForm.setColWidths("*", "*", "*");
jobForm.setTitleOrientation(TitleOrientation.TOP);
jobForm.setItemHoverWidth(300);
SelectItem owner = new SelectItem(WorkflowJobDataSource.FIELD_OWNER);
owner.setOptionDataSource(UserDataSource.getInstance());
owner.setValueField(UserDataSource.FIELD_ID);
owner.setDisplayField(UserDataSource.FIELD_USERNAME);
// AutoFitTextAreaItem note = new AutoFitTextAreaItem(WorkflowJobDataSource.FIELD_NOTE);
// There is a bug in AutoFitTextAreaItem. It does not resize properly.
TextAreaItem note = new TextAreaItem(WorkflowJobDataSource.FIELD_NOTE);
note.setStartRow(true);
note.setColSpan("*");
note.setWidth("*");
// title tooltip is broken in SmartGWT 4.0
final FormItemIcon jobHelpIcon = new FormItemIcon();
jobHelpIcon.setSrc("[SKIN]/actions/help.png");
jobHelpIcon.setTabIndex(-1);
jobHelpIcon.setShowIfCondition(new FormItemIfFunction() {
@Override
public boolean execute(FormItem item, Object value, DynamicForm form) {
String hint = jobForm.getValueAsString(WorkflowJobDataSource.FIELD_PROFILE_HINT);
jobHelpIcon.setPrompt(hint);
return hint != null;
}
});
final TextItem label = new TextItem(WorkflowJobDataSource.FIELD_LABEL);
label.setColSpan("*");
label.setWidth("*");
label.setIcons(jobHelpIcon);
jobForm.setFields(label,
new SelectItem(WorkflowJobDataSource.FIELD_STATE),
new SelectItem(WorkflowJobDataSource.FIELD_PRIORITY),
new TextItem(WorkflowJobDataSource.FIELD_PROFILE_ID),
owner,
new TextItem(WorkflowJobDataSource.FIELD_FINANCED),
new TextItem(WorkflowJobDataSource.FIELD_ID),
new TextItem(WorkflowJobDataSource.FIELD_CREATED),
new TextItem(WorkflowJobDataSource.FIELD_MODIFIED),
note
);
jobForm.addItemChangedHandler(new ItemChangedHandler() {
@Override
public void onItemChanged(ItemChangedEvent event) {
refreshState();
}
});
jobForm.addSubmitValuesHandler(new SubmitValuesHandler() {
@Override
public void onSubmitValues(SubmitValuesEvent event) {
if (handler != null) {
handler.onSave(WorkflowJobFormView.this);
}
}
});
jobForm.setSaveOnEnter(true);
return jobForm;
}
private Widget createTaskList() {
taskView = new ListGrid();
taskView.setCanSort(false);
taskView.setDataFetchMode(FetchMode.BASIC);
taskView.setGenerateDoubleClickOnEnter(true);
ListGridPersistance taskViewPersistance = new ListGridPersistance("WorkflowJobFormView.taskList", taskView);
ResultSet rs = new ResultSet();
rs.setCriteriaPolicy(CriteriaPolicy.DROPONCHANGE);
rs.setUseClientFiltering(false);
rs.setUseClientSorting(true);
taskView.setDataProperties(rs);
taskView.setDataSource(WorkflowTaskDataSource.getInstance(),
new ListGridField(WorkflowTaskDataSource.FIELD_LABEL),
new ListGridField(WorkflowTaskDataSource.FIELD_OWNER, 50),
new ListGridField(WorkflowTaskDataSource.FIELD_STATE, 50),
new ListGridField(WorkflowTaskDataSource.FIELD_TYPE),
new ListGridField(WorkflowTaskDataSource.FIELD_PRIORITY, 60),
new ListGridField(WorkflowTaskDataSource.FIELD_CREATED, 100),
new ListGridField(WorkflowTaskDataSource.FIELD_MODIFIED, 100),
new ListGridField(WorkflowTaskDataSource.FIELD_ID, 30),
new ListGridField(WorkflowTaskDataSource.FIELD_NOTE)
);
taskView.getField(WorkflowTaskDataSource.FIELD_TYPE).setHidden(true);
taskView.getField(WorkflowTaskDataSource.FIELD_PRIORITY).setHidden(true);
taskView.getField(WorkflowTaskDataSource.FIELD_CREATED).setHidden(true);
taskView.getField(WorkflowTaskDataSource.FIELD_MODIFIED).setHidden(true);
taskView.getField(WorkflowTaskDataSource.FIELD_ID).setHidden(true);
taskView.getField(WorkflowTaskDataSource.FIELD_NOTE).setHidden(true);
taskView.setViewState(taskViewPersistance.getViewState());
taskView.addSelectionUpdatedHandler(new SelectionUpdatedHandler() {
@Override
public void onSelectionUpdated(SelectionUpdatedEvent event) {
refreshState();
}
});
taskView.addRecordDoubleClickHandler(new RecordDoubleClickHandler() {
@Override
public void onRecordDoubleClick(RecordDoubleClickEvent event) {
ActionEvent evt = new ActionEvent(actionSource);
if (editTaskAction.accept(evt)) {
editTaskAction.performAction(evt);
}
}
});
this.editTaskAction = new AbstractAction(
i18n.WorkflowJob_FormView_EditTaskAction_Title(),
"[SKIN]/actions/edit.png",
i18n.WorkflowJob_FormView_EditTaskAction_Hint()) {
@Override
public boolean accept(ActionEvent event) {
return taskView.getSelectedRecords().length == 1;
}
@Override
public void performAction(ActionEvent event) {
ListGridRecord selectedRecord = taskView.getSelectedRecord();
handler.onGotoTask(selectedRecord.getAttribute(WorkflowTaskDataSource.FIELD_ID));
}
};
Menu ctxMenu = Actions.createMenu();
ctxMenu.addItem(createAddTaskMenuItem());
ctxMenu.addItem(Actions.asMenuItem(editTaskAction, actionSource, false));
taskView.setContextMenu(ctxMenu);
Actions.fixListGridContextMenu(taskView);
return taskView;
}
private MenuItem createAddTaskMenuItem() {
addTaskMenu = new Menu();
addTaskMenu.addItemClickHandler(new ItemClickHandler() {
@Override
public void onItemClick(ItemClickEvent event) {
if (handler != null) {
Record taskDef = event.getRecord();
Record newTask = new Record();
newTask.setAttribute(WorkflowModelConsts.TASK_JOBID,
jobForm.getValue(WorkflowModelConsts.JOB_ID));
newTask.setAttribute(WorkflowModelConsts.TASK_PROFILENAME,
taskDef.getAttribute(WorkflowProfileConsts.NAME));
handler.onCreateNewTask(WorkflowJobFormView.this, newTask);
}
}
});
MenuItem addTaskMenuItem = Actions.asMenuItem(new AbstractAction(
i18n.WorkflowJob_FormView_AddTaskAction_Title(),
"[SKIN]/actions/add.png",
i18n.WorkflowJob_FormView_AddTaskAction_Hint()) {
@Override
public void performAction(ActionEvent event) {
}
}, taskView);
addTaskMenuItem.setSubmenu(addTaskMenu);
return addTaskMenuItem;
}
private Widget createMaterialList() {
materialView = new WorkflowMaterialView(i18n, true);
return materialView.getWidget();
}
}