package pl.net.bluesoft.rnd.processtool.ui.basewidgets;
import com.vaadin.data.Item;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.BeanItemContainer;
import com.vaadin.event.ItemClickEvent;
import com.vaadin.terminal.Sizeable;
import com.vaadin.ui.*;
import com.vaadin.ui.themes.Reindeer;
import org.aperteworkflow.util.vaadin.VaadinUtility;
import pl.net.bluesoft.rnd.processtool.ProcessToolContext;
import pl.net.bluesoft.rnd.processtool.model.BpmTask;
import pl.net.bluesoft.rnd.processtool.model.ProcessInstance;
import pl.net.bluesoft.rnd.processtool.model.processdata.ProcessComment;
import pl.net.bluesoft.rnd.processtool.model.processdata.ProcessComments;
import pl.net.bluesoft.rnd.processtool.ui.widgets.ProcessToolDataWidget;
import pl.net.bluesoft.rnd.processtool.ui.widgets.ProcessToolVaadinRenderable;
import pl.net.bluesoft.rnd.processtool.ui.widgets.ProcessToolWidget;
import pl.net.bluesoft.rnd.processtool.ui.widgets.annotations.*;
import pl.net.bluesoft.rnd.processtool.ui.widgets.impl.BaseProcessToolVaadinWidget;
import pl.net.bluesoft.rnd.processtool.ui.widgets.impl.BaseProcessToolWidget;
import pl.net.bluesoft.util.lang.FormatUtil;
import pl.net.bluesoft.util.lang.Formats;
import pl.net.bluesoft.util.lang.Lang;
import java.util.*;
import static pl.net.bluesoft.rnd.processtool.ui.basewidgets.ProcessHistoryWidget.label;
import static pl.net.bluesoft.util.lang.Formats.formatFullDate;
import static pl.net.bluesoft.util.lang.Formats.nvl;
/**
* @author tlipski@bluesoft.net.pl
*/
@AliasName(name = "ProcessComments")
@AperteDoc(humanNameKey="widget.process_comments.name", descriptionKey="widget.process_comments.description")
@ChildrenAllowed(false)
@PermissionsUsed({
@Permission(key="ADD", desc="widget.process_comments.permission.desc.ADD"),
@Permission(key="EDIT", desc="widget.process_comments.permission.desc.EDIT"),
@Permission(key="EDIT_ALL", desc="widget.process_comments.permission.desc.EDIT_ALL"),
@Permission(key="VIEW", desc="widget.process_comments.permission.desc.VIEW")
})
@WidgetGroup("base-widgets")
public class ProcessCommentsWidget extends BaseProcessToolVaadinWidget implements ProcessToolVaadinRenderable, ProcessToolDataWidget {
private BeanItemContainer<ProcessComment> bic = new BeanItemContainer<ProcessComment>(ProcessComment.class);
@AutoWiredProperty(required = false)
@AperteDoc(
humanNameKey="widget.process_comments.property.table.name",
descriptionKey="widget.process_comments.property.table.description"
)
private Boolean table;
@AutoWiredProperty
private Boolean mustAddComment;
private String processState = null;
private Panel commentsPanel;
@Override
public void loadData(BpmTask task) {
ProcessInstance pi = task.getProcessInstance().getRootProcessInstance();
ProcessComments comments = pi.findAttributeByClass(ProcessComments.class);
if (comments != null) {
List<ProcessComment> lst = new ArrayList<ProcessComment>(comments.getComments());
Collections.sort(lst, new Comparator<ProcessComment>() {
@Override
public int compare(ProcessComment o1, ProcessComment o2) {
return -o1.getCreateTime().compareTo(o2.getCreateTime());
}
});
for (ProcessComment cmt : lst) {
bic.addBean(cmt);
}
}
processState = task.getTaskName();
}
@Override
public Component render() {
VerticalLayout vl = new VerticalLayout();
if (hasPermission("ADD", "EDIT", "EDIT_ALL", "VIEW")) {
if (nvl(table, false)) {
final Table table = new Table();
table.setContainerDataSource(bic);
table.setVisibleColumns(new Object[]{"author", "createTime"});
table.setWidth("100%");
table.addGeneratedColumn("author", new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, Object itemId, Object columnId) {
BeanItem<ProcessComment> item = (BeanItem<ProcessComment>) source.getItem(itemId);
return new Label(item.getBean().getAuthor().getRealName());
}
});
table.addGeneratedColumn("createTime", new Table.ColumnGenerator() {
@Override
public Component generateCell(Table source, Object itemId, Object columnId) {
BeanItem<ProcessComment> item = (BeanItem<ProcessComment>) source.getItem(itemId);
return new Label(FormatUtil.formatFullDate(item.getBean().getCreateTime()));
}
});
table.setImmediate(true);
table.setSelectable(true);
for (Object o : table.getVisibleColumns()) {
table.setColumnHeader(o, getMessage("processdata.comments.comment.table." + o));
}
vl.addComponent(table);
table.addListener(
new ItemClickEvent.ItemClickListener() {
@Override
public void itemClick(ItemClickEvent event) {
if (event.isDoubleClick()) {
Component component = event.getComponent();
final BeanItem<ProcessComment> bi = bic.getItem(event.getItemId());
displayCommentDetails(component, bi);
}
}
});
table.setHeight("200px");
} else {
commentsPanel = new Panel();
commentsPanel.setStyleName(Reindeer.PANEL_LIGHT);
commentsPanel.setWidth("100%");
commentsPanel.setHeight("240px");
refreshData();
vl.addComponent(commentsPanel);
}
}
final Button addCommentButton = new Button(getMessage("processdata.comments.comment.add"));
addCommentButton.addStyleName("default");
addCommentButton.addListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
ProcessComment pc = new ProcessComment();
ProcessToolContext ctx = ProcessToolContext.Util.getThreadProcessToolContext();
pc.setAuthor(bpmSession.getUser(ctx));
pc.setAuthorSubstitute(bpmSession.getSubstitutingUser(ctx));
pc.setCreateTime(new Date());
pc.setProcessState(processState);
final BeanItem<ProcessComment> bi = new BeanItem<ProcessComment>(pc);
displayCommentDetails(addCommentButton, bi);
}
});
vl.addComponent(addCommentButton);
addCommentButton.setEnabled(isOwner && hasPermission("ADD"));
return vl;
}
private void refreshData() {
if (commentsPanel == null) return;
VerticalLayout layout = (VerticalLayout) commentsPanel.getContent();
layout.removeAllComponents();
layout.setSpacing(true);
for (ProcessComment pc : bic.getItemIds()) {
HorizontalLayout hl;
hl = new HorizontalLayout();
hl.addStyleName("comment-header");
hl.setSpacing(true);
hl.setWidth("100%");
String authorLabel = pc.getAuthor() != null ? pc.getAuthor().getRealName() : "System";
if (pc.getAuthorSubstitute() != null) {
authorLabel = (pc.getAuthorSubstitute() != null ? pc.getAuthorSubstitute().getRealName() : "System")
+ " ( " + getMessage("processdata.comments.substituting") + " "
+ authorLabel
+ " )";
}
hl.addComponent(label("<b class=\"header-author\">" + authorLabel + "</b>", 150));
hl.addComponent(label("<b class=\"header-time\">" + FormatUtil.formatFullDate(pc.getCreateTime()) + "</b>", 150));
// hl.addComponent(label(pc.getComment(), 450));
Label spacer = new Label("");
hl.addComponent(spacer);
hl.setExpandRatio(spacer, 1);
layout.addComponent(hl);
hl = new HorizontalLayout();
hl.addStyleName("comment-body");
hl.setWidth("100%");
hl.setSpacing(true);
hl.setMargin(new Layout.MarginInfo(false, false, true, true));
Label l = new Label(pc.getBody(), Label.CONTENT_XHTML);
l.setWidth("100%");
hl.addComponent(l);
hl.setExpandRatio(l, 1.0f);
layout.addComponent(hl);
}
}
private void displayCommentDetails(Component component, final BeanItem<ProcessComment> bi) {
final Form f = getCommentDetailsForm(bi,
isOwner &&
(hasPermission("EDIT") && Lang.equals(
bi.getBean().getAuthor().getId(),
bpmSession.getUser(ProcessToolContext.Util.getThreadProcessToolContext()).getId()))
|| bi.getBean().getId() == null
|| hasPermission("EDIT_ALL"));
final Window newCommentWindow = new Window(getMessage("processdata.comments.comment.edit.title"));
newCommentWindow.setModal(true);
HorizontalLayout hl = new HorizontalLayout();
Button okButton = new Button(getMessage("button.ok"));
okButton.addStyleName("default");
okButton.addListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
if (f.isValid()) {
f.commit();
bic.addBean(bi.getBean());
refreshData();
newCommentWindow.getParent().removeWindow(newCommentWindow);
}
else {
StringBuilder sb = new StringBuilder("<ul>");
for (Object propertyId : f.getItemPropertyIds()) {
Field field = f.getField(propertyId);
if (!field.isValid() && field.isRequired()) {
sb.append("<li>").append(field.getRequiredError()).append("</li>");
}
}
sb.append("</ul>");
VaadinUtility.validationNotification(getApplication(), i18NSource, sb.toString());
}
}
});
hl.addComponent(okButton);
okButton.setEnabled(!f.isReadOnly());
Button cancelButton = new Button(getMessage("button.cancel"));
cancelButton.addStyleName("default");
cancelButton.addListener(new Button.ClickListener() {
@Override
public void buttonClick(Button.ClickEvent event) {
newCommentWindow.getParent().removeWindow(newCommentWindow);
}
});
hl.addComponent(cancelButton);
VerticalLayout vl = new VerticalLayout();
vl.addComponent(new Label(getMessage("process.comments.edit.help"), Label.CONTENT_XHTML));
// vl.addComponent(new HorizontalLayout() {{
// addComponent(f);
// setMargin(true);
// }});
vl.addComponent(f);
vl.addComponent(hl);
vl.setComponentAlignment(hl, Alignment.BOTTOM_CENTER);
vl.setMargin(true);
// hl.setMargin(true);
hl.setSpacing(true);
// vl.setExpandRatio(f, 1f);
// vl.setExpandRatio(hl, 1f);
vl.setWidth(600, Sizeable.UNITS_PIXELS);
newCommentWindow.setContent(vl);
newCommentWindow.setResizable(true);
// newCommentWindow.setImmediate(true);
component.getApplication().getMainWindow().addWindow(newCommentWindow);
}
private Form getCommentDetailsForm(final BeanItem<ProcessComment> bi, boolean editable) {
Form f = new Form();
f.setReadOnly(!editable);
f.setWriteThrough(false);
f.setInvalidCommitted(false);
f.setFormFieldFactory(new DefaultFieldFactory() {
@Override
public Field createField(Item item, Object propertyId, Component uiContext) {
// Field f = super.createField(item, propertyId, uiContext);
Field f = null;
// if ("comment".equals(propertyId)) {
// TextField tf = new TextField();
// tf.setRequired(true);
// tf.setRequiredError(getMessage("processdata.comments.comment.comment.required"));
// tf.setNullRepresentation("");
// tf.setInputPrompt(getMessage("processdata.comments.comment.comment.prompt"));
// tf.setWidth(400, Sizeable.UNITS_PIXELS);
// f = tf;
// } else
if ("body".equals(propertyId)) {
RichTextArea rta = new RichTextArea();
rta.setRequired(true);
rta.setNullRepresentation("");
rta.setRequiredError(getMessage("processdata.comments.comment.body.required"));
rta.setWidth(400, Sizeable.UNITS_PIXELS);
rta.focus();
f = rta;
}
if (f != null)
f.setCaption(getMessage("processdata.comments.comment.form." + propertyId));
return f;
}
});
f.setItemDataSource(bi);
f.setVisibleItemProperties(Arrays.asList("body"));
TextField field = new TextField();
field.setValue(formatFullDate(bi.getBean().getCreateTime()));
field.setCaption(getMessage("processdata.comments.comment.form.createTime"));
field.setReadOnly(true);
f.addField("createTime", field);
field = new TextField();
field.setValue(bi.getBean().getAuthor().getRealName());
field.setCaption(getMessage("processdata.comments.comment.form.author"));
field.setReadOnly(true);
f.addField("author", field);
f.setWidth(600, Sizeable.UNITS_PIXELS);
if (!editable) {
for (Object o : f.getItemPropertyIds()) {
Field tmpField = f.getField(o);
tmpField.setReadOnly(true);
}
}
return f;
}
@Override
public Collection<String> validateData(BpmTask task, boolean skipRequired) {
if ("true".equals(getAttributeValue("mustAddComment"))) {
//look for a fresh comment or added in this state
for (ProcessComment pc : bic.getItemIds()) {
if (pc.getId() == null)
return null;
if (task.getTaskName().equals(pc.getProcessState())) {
return null;
}
}
return Arrays.asList(getMessage("please.add.comment"));
} else {
return null;
}
}
@Override
public void saveData(BpmTask task) {
ProcessInstance pi = task.getProcessInstance().getRootProcessInstance();
ProcessComments comments = pi.findAttributeByClass(ProcessComments.class);
if (comments == null) {
comments = new ProcessComments();
comments.setProcessInstance(pi);
comments.setKey(ProcessComments.class.getName());
pi.getProcessAttributes().add(comments);
}
comments.setComments(new HashSet());
for (ProcessComment pc : bic.getItemIds()) {
comments.getComments().add(pc);
pc.setComments(comments);
}
}
@Override
public void addChild(ProcessToolWidget child) {
throw new IllegalArgumentException("children are not supported in this widget");
}
public String getCaption() {
return caption;
}
public void setCaption(String caption) {
this.caption = caption;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
public Boolean getMustAddComment() {
return mustAddComment;
}
public void setMustAddComment(Boolean mustAddComment) {
this.mustAddComment = mustAddComment;
}
}