package org.jbpm.gd.jpdl.properties; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IImportDeclaration; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageDeclaration; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CCombo; import org.eclipse.swt.custom.TableEditor; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.views.properties.tabbed.TabbedPropertySheetWidgetFactory; import org.jboss.tools.jbpm.util.AutoResizeTableLayout; import org.jbpm.gd.common.model.GenericElement; import org.jbpm.gd.jpdl.Logger; import org.jbpm.gd.jpdl.dialog.ChooseDelegationClassDialog; import org.jbpm.gd.jpdl.model.Delegation; import org.jbpm.gd.jpdl.util.ProjectFinder; public class DelegationConfigurationComposite implements KeyListener, SelectionListener, FocusListener { public static DelegationConfigurationComposite create( TabbedPropertySheetWidgetFactory widgetFactory, Composite parent, ChooseDelegationClassDialog dialog) { DelegationConfigurationComposite result = new DelegationConfigurationComposite(); result.chooseDelegationClassDialog = dialog; result.widgetFactory = widgetFactory; result.parent = parent; result.create(); return result; } private TabbedPropertySheetWidgetFactory widgetFactory; private Composite parent; private ChooseDelegationClassDialog chooseDelegationClassDialog; private Delegation delegation; private Label nameLabel; private Text nameText; private Button searchButton; private Label configTypeLabel; private CCombo configTypeCombo; private HashMap configAreaPages = new HashMap(); private LabelComposite messageLabel; private TextComposite constructorTextComposite; private TextComposite compatibilityTextComposite; private TableComposite fieldTableComposite; private TableComposite beanTableComposite; private DelegationConfigurationComposite() {} public void setDelegation(Delegation delegation) { if (this.delegation == delegation) return; unhookListeners(); this.delegation = delegation; clearControls(); if (delegation != null) { updateControls(); hookListeners(); } } private void hookListeners() { nameText.addKeyListener(this); searchButton.addSelectionListener(this); configTypeCombo.addSelectionListener(this); constructorTextComposite.text.addFocusListener(this); compatibilityTextComposite.text.addFocusListener(this); } private void unhookListeners() { nameText.removeKeyListener(this); searchButton.removeSelectionListener(this); configTypeCombo.removeSelectionListener(this); constructorTextComposite.text.removeFocusListener(this); compatibilityTextComposite.text.removeFocusListener(this); } private void clearControls() { nameText.setText(""); configTypeCombo.setText("Field"); showPage("Message"); messageLabel.setText(""); fieldTableComposite.table.removeAll(); beanTableComposite.table.removeAll(); constructorTextComposite.text.setText(""); compatibilityTextComposite.text.setText(""); } private void showPage(String key) { Iterator iter = configAreaPages.keySet().iterator(); while (iter.hasNext()) { String candidate = (String)iter.next(); ((DelegationConfigurationWidget)configAreaPages.get(candidate)).setVisible(candidate.equals(key)); } } private void updateControls() { nameText.setText(getDelegationClassName()); configTypeCombo.setText(fromConfigType(getDelegationConfigType())); updatePageBook(); } private void updatePageBook() { IType type = getClassFor(nameText.getText()); updateFieldTableComposite(type); updateBeanTableComposite(type); updateConstructorTextComposite(); updateCompatibilityTextComposite(); updateVisiblePage(type != null); } private void updateFieldTableComposite(IType type) { if (type == null) return; List list = getFields(type); for (int i = 0; i < list.size(); i++) { TableItem item = new TableItem(fieldTableComposite.table, SWT.NONE); item.setText(0, (String)list.get(i)); } if ("field".equals(getDelegationConfigType())) { updateTableItems(fieldTableComposite.table.getItems()); } } private void updateTableItems(TableItem[] items) { GenericElement[] elements = delegation.getGenericElements(); for (int i = 0; i < elements.length; i++) { for (int j = 0; j < items.length; j++) { String name = elements[i].getName() == null ? "" : elements[i].getName(); String value = elements[i].getValue() == null ? "" : elements[i].getValue(); if (name.equals(items[j].getText(0))) { items[j].setChecked(true); items[j].setText(1, value); items[j].setData(elements[i]); break; } } } } private void updateBeanTableComposite(IType type) { if (type == null) return; List list = getSetters(type); for (int i = 0; i < list.size(); i++) { TableItem item = new TableItem(beanTableComposite.table, SWT.NONE); item.setText(0, (String)list.get(i)); } if ("bean".equals(getDelegationConfigType())) { updateTableItems(beanTableComposite.table.getItems()); } } private void updateConstructorTextComposite() { boolean valid = "constructor".equals(getDelegationConfigType()); constructorTextComposite.text.setText(valid ? getDelegationConfigString() : ""); } private void updateCompatibilityTextComposite() { boolean valid = "configuration-property".equals(getDelegationConfigType()); constructorTextComposite.text.setText(valid ? getDelegationConfigString() : ""); } private void updateVisiblePage(boolean validClass) { if (!validClass) { showInvalidTypeMessage(); } else { handleValidType(); } } private String getDelegationConfigType() { return delegation.getConfigType() == null ? "field" : delegation.getConfigType(); } private String getDelegationClassName() { return delegation.getClassName() == null ? "" : delegation.getClassName(); } private String getDelegationConfigString() { return delegation.getConfigInfo() == null ? "" : delegation.getConfigInfo(); } private void create() { nameLabel = widgetFactory.createLabel(parent, "Class Name"); nameText = widgetFactory.createText(parent, ""); searchButton = widgetFactory.createButton(parent, "Search...", SWT.PUSH); configTypeLabel = widgetFactory.createLabel(parent, "Config Type"); configTypeCombo = widgetFactory.createCCombo(parent); configTypeCombo.setItems(getConfigurationTypes()); configTypeCombo.setEditable(false); createPages(parent); nameLabel.setLayoutData(createNameLabelLayoutData()); nameText.setLayoutData(createNameTextLayoutData()); searchButton.setLayoutData(createSearchButtonLayoutData()); configTypeLabel.setLayoutData(createConfigTypeLabelLayoutData()); configTypeCombo.setLayoutData(createConfigTypeComboLayoutData()); } private void createPages(Composite composite) { messageLabel = new LabelComposite(); messageLabel.create(composite); configAreaPages.put("Message", messageLabel); fieldTableComposite = new TableComposite(); fieldTableComposite.create(composite); configAreaPages.put("Field", fieldTableComposite); beanTableComposite = new TableComposite(); beanTableComposite.create(composite); configAreaPages.put("Bean", beanTableComposite); constructorTextComposite = new TextComposite(); constructorTextComposite.create(composite); configAreaPages.put("Constructor", constructorTextComposite); compatibilityTextComposite = new TextComposite(); compatibilityTextComposite.create(composite); configAreaPages.put("Compatibility", compatibilityTextComposite); } private String[] getConfigurationTypes() { return new String[] { "Field", "Bean", "Constructor", "Compatibility" }; } private FormData createNameLabelLayoutData() { FormData result = new FormData(); result.left = new FormAttachment(0, 0); result.top = new FormAttachment(0, 2); return result; } private FormData createNameTextLayoutData() { FormData result = new FormData(); result.left = new FormAttachment(nameLabel, 0); result.right = new FormAttachment(searchButton, 0); result.top = new FormAttachment(0, 0); return result; } private FormData createSearchButtonLayoutData() { FormData result = new FormData(); result.right = new FormAttachment(configTypeLabel, 0); result.top = new FormAttachment(0, -3); return result; } private FormData createConfigTypeLabelLayoutData() { FormData result = new FormData(); result.right = new FormAttachment(configTypeCombo, 0); result.top = new FormAttachment(0, 2); return result; } private FormData createConfigTypeComboLayoutData() { FormData result = new FormData(); result.right = new FormAttachment(100, 0); result.top = new FormAttachment(0, -2); return result; } public void keyPressed(KeyEvent e) { } public void keyReleased(KeyEvent e) { if (e.widget == nameText) { handleNameTextChange(); } } public void widgetDefaultSelected(SelectionEvent e) { } private void handleNameTextChange() { String newName = nameText.getText(); if (newName.equals(delegation.getClassName())) return; delegation.setClassName(newName); if (delegation.getConfigInfo() != null) { delegation.setConfigInfo(null); } GenericElement[] genericElements = delegation.getGenericElements(); fieldTableComposite.table.removeAll(); beanTableComposite.table.removeAll(); for (int i = 0; i < genericElements.length; i++) { delegation.removeGenericElement(genericElements[i]); } updatePageBook(); } private void handleValidType() { String configType = delegation.getConfigType(); if ("field".equals(configType)) { handleFieldConfigType(); } else if ("bean".equals(configType)) { handleBeanConfigType(); } else if ("constructor".equals(configType)) { handleConstructorConfigType(); } else if ("configuration-property".equals(configType)) { handleCompatibilityConfigType(); } } private void handleFieldConfigType() { if (fieldTableComposite.table.getItemCount() == 0) { messageLabel.setText("The class does not have any fields"); showPage("Message"); } else { showPage("Field"); restoreConfigElements(fieldTableComposite.table.getItems()); } } private void restoreConfigElements(TableItem[] items) { if (delegation.getGenericElements().length == 0) { for (int i = 0; i < items.length; i++) { if (items[i].getChecked()) { addGenericElement(items[i]); } } } } private List getFields(IType type) { List result = new ArrayList(); try { List types = getTypes(type); for (int i = 0; i < types.size(); i++) { IType subType = (IType)types.get(i); IField[] fields = subType.getFields(); for (int j = 0; j < fields.length; j++) { if (!Flags.isStatic(fields[j].getFlags())) { String fieldName = fields[j].getElementName(); if (!result.contains(fieldName)) { result.add(fieldName); } } } } } catch (JavaModelException e) { Logger.logError("Error while getting the fields for type " + type + ".", e); } return result; } private IType getSupertype(IType targetType) throws JavaModelException { if (targetType == null) return null; String name = targetType.getSuperclassName(); if (name == null) return null; IType result = getClassFor(name); if (result != null) return result; ICompilationUnit compilationUnit = targetType.getCompilationUnit(); if (compilationUnit == null) return null; IPackageDeclaration[] packageDeclarations = compilationUnit.getPackageDeclarations(); if (packageDeclarations != null && packageDeclarations.length > 0) { String qualifiedName = packageDeclarations[0].getElementName() + "." + name; result = getClassFor(qualifiedName); if (result != null) return result; } IImportDeclaration[] importDeclarations = compilationUnit.getImports(); if (importDeclarations == null) return null; for (int i = 0; i < importDeclarations.length; i++) { String declaration = importDeclarations[i].getElementName(); if (declaration.endsWith(name)) { result = getClassFor(declaration); if (result != null) return result; } else if (declaration.endsWith(".*")) { String qualifiedName = declaration.substring(0, declaration.length() - 1) + name; result = getClassFor(qualifiedName); if (result != null) return result; } } return null; } private List getTypes(IType targetType) { List types = new ArrayList(); IType type = targetType; while (type != null && !"java.lang.Object".equals(type.getFullyQualifiedName())) { try { types.add(type); type = getSupertype(type); } catch (JavaModelException e) { Logger.logError("Error while looking up the supertypes of " + targetType.getFullyQualifiedName() + ".", e); } } return types; } private void handleBeanConfigType() { if (beanTableComposite.table.getItemCount() == 0) { messageLabel.setText("The class does not have any setters"); showPage("Message"); } else { showPage("Bean"); restoreConfigElements(beanTableComposite.table.getItems()); } } private List getSetters(IType type) { List result = new ArrayList(); try { List types = getTypes(type); for (int i = 0; i < types.size(); i++) { IType subType = (IType)types.get(i); IMethod[] methods = subType.getMethods(); for (int j = 0; j < methods.length; j++) { if (methods[j].getElementName().startsWith("set")) { StringBuffer buff = new StringBuffer(methods[j].getElementName().substring(3)); buff.setCharAt(0, Character.toLowerCase(buff.charAt(0))); String methodName = buff.toString(); if (!result.contains(methodName)) { result.add(methodName); } } } } } catch (JavaModelException e) { Logger.logError("Error while getting the setters for type " + type + ".", e); } return result; } private void handleConstructorConfigType() { showPage("Constructor"); if (delegation.getConfigInfo() == null) { delegation.setConfigInfo(constructorTextComposite.text.getText()); } else { constructorTextComposite.text.setText(delegation.getConfigInfo()); } } private void handleCompatibilityConfigType() { showPage("Compatibility"); if (delegation.getConfigInfo() == null) { delegation.setConfigInfo(compatibilityTextComposite.text.getText()); } else { compatibilityTextComposite.text.setText(delegation.getConfigInfo()); } } private void showInvalidTypeMessage() { messageLabel.setText("The class does not exist on the project classpath."); showPage("Message"); } private IType getClassFor(String className) { if (className == null) return null; try { return ProjectFinder.getCurrentProject().findType(className); } catch (JavaModelException e) { e.printStackTrace(); return null; } } private void addGenericElement(TableItem item) { String name = item.getText(0) == null ? "" : item.getText(0); String value = item.getText(1) == null ? "" : item.getText(1); GenericElement genericElement = (GenericElement)delegation.getFactory().createById("org.jbpm.gd.jpdl.genericElement"); genericElement.setName(name); genericElement.setValue(value); delegation.addGenericElement(genericElement); item.setData(genericElement); } private void removeGenericElement(TableItem item) { GenericElement genericElement = (GenericElement)item.getData(); if (genericElement != null) { delegation.removeGenericElement(genericElement); } } public void widgetSelected(SelectionEvent e) { if (e.widget == searchButton) { handleSearchButtonSelected(); } else if (e.widget == configTypeCombo) { handleConfigTypeComboChanged(); } } private void handleConfigTypeComboChanged() { String newConfigType = toConfigType(configTypeCombo.getText()); if (delegation.getConfigType().equals(newConfigType)) return; delegation.setConfigInfo(null); GenericElement[] genericElements = delegation.getGenericElements(); for (int i = 0; i < genericElements.length; i++) { delegation.removeGenericElement(genericElements[i]); } delegation.setConfigType(newConfigType); updateVisiblePage(getClassFor(nameText.getText()) != null); } private void handleSearchButtonSelected() { String chosenClass = chooseDelegationClassDialog.openDialog(); if (chosenClass != null) { nameText.setText(chosenClass); handleNameTextChange(); } } private String toConfigType(String configType) { if ("Field".equals(configType)) return "field"; if ("Bean".equals(configType)) return "bean"; if ("Constructor".equals(configType)) return "constructor"; if ("Compatibility".equals(configType)) return "configuration-property"; return null; } private String fromConfigType(String configType) { if ("field".equals(configType)) return "Field"; if ("bean".equals(configType)) return "Bean"; if ("constructor".equals(configType)) return "Constructor"; if ("configuration-property".equals(configType)) return "Compatibility"; return null; } public void focusGained(FocusEvent e) { } public void focusLost(FocusEvent e) { if (e.widget == constructorTextComposite.text) { delegation.setConfigInfo(constructorTextComposite.text.getText()); } else if (e.widget == compatibilityTextComposite.text) { delegation.setConfigInfo(compatibilityTextComposite.text.getText()); } } public Delegation getDelegation() { return delegation; } private interface DelegationConfigurationWidget { void setVisible(boolean visible); } private class LabelComposite implements DelegationConfigurationWidget { private Label label; private void create(Composite parent) { label = widgetFactory.createLabel(parent, ""); label.setLayoutData(createLabelLayoutData()); } private void setText(String message) { label.setText(message); } public void setVisible(boolean visible) { label.setVisible(visible); } private FormData createLabelLayoutData() { FormData result = new FormData(); result.left = new FormAttachment(0, 0); result.right = new FormAttachment(100, 0); result.top = new FormAttachment(configTypeCombo, 2); return result; } } private class TextComposite implements DelegationConfigurationWidget { private Label label; private Text text; private void create(Composite parent) { label = widgetFactory.createLabel(parent, "Config Info"); text = widgetFactory.createText(parent, "", SWT.MULTI | SWT.V_SCROLL); label.setLayoutData(createLabelLayoutData()); text.setLayoutData(createTextLayoutData()); } private FormData createLabelLayoutData() { FormData result = new FormData(); result.left = new FormAttachment(0, 0); result.top = new FormAttachment(configTypeCombo, 2); return result; } private FormData createTextLayoutData() { FormData result = new FormData(); result.top = new FormAttachment(configTypeCombo, 0); result.left = new FormAttachment(nameText, 0); result.left.alignment = SWT.LEFT; result.right = new FormAttachment(100, 0); result.bottom = new FormAttachment(100, 0); return result; } public void setVisible(boolean visible) { label.setVisible(visible); text.setVisible(visible); } } private class TableComposite implements FocusListener, MouseListener, SelectionListener, DelegationConfigurationWidget { private Label label; private Table table; private TableEditor valueEditor; private Text valueText; private void create(Composite parent) { label = widgetFactory.createLabel(parent, "Config Info"); table = widgetFactory.createTable(parent, SWT.CHECK | SWT.FULL_SELECTION | SWT.V_SCROLL); label.setLayoutData(createLabelLayoutData()); table.setLayoutData(createTableLayoutData()); table.setHeaderVisible(true); table.setLinesVisible(true); table.addSelectionListener(this); table.addMouseListener(this); AutoResizeTableLayout handlerConfigBeanTableLayout = new AutoResizeTableLayout(table); handlerConfigBeanTableLayout.addColumnData(new ColumnWeightData(40)); handlerConfigBeanTableLayout.addColumnData(new ColumnWeightData(60)); table.setLayout(handlerConfigBeanTableLayout); TableColumn handlerConfigBeanTableNameColumn = new TableColumn(table, SWT.NONE); handlerConfigBeanTableNameColumn.setText("Name"); TableColumn handlerConfigBeanTableValueColumn = new TableColumn(table, SWT.NONE); handlerConfigBeanTableValueColumn.setText("Value"); createEditor(); } private FormData createLabelLayoutData() { FormData result = new FormData(); result.left = new FormAttachment(0, 0); result.top = new FormAttachment(configTypeCombo, 2); return result; } private FormData createTableLayoutData() { FormData result = new FormData(); result.top = new FormAttachment(configTypeCombo, 0); result.left = new FormAttachment(nameText, 0); result.left.alignment = SWT.LEFT; result.right = new FormAttachment(100, 0); result.bottom = new FormAttachment(100, 0); return result; } private void createEditor() { valueEditor = new TableEditor(table); valueText = new Text(table, SWT.NORMAL); valueText.setVisible(false); valueText.setText(""); valueEditor.minimumWidth = valueText.getSize().x; valueEditor.horizontalAlignment = SWT.LEFT; valueEditor.grabHorizontal = true; } private void doEdit() { if (valueText.isVisible()) endEdit(); if (table.getSelectionIndex() == -1) return; TableItem selection = table.getItem(table.getSelectionIndex()); String value = selection.getText(1); valueText.setText(value == null ? "" : value); valueEditor.setEditor(valueText, selection, 1); valueText.setVisible(true); valueText.selectAll(); valueText.setFocus(); valueText.addFocusListener(this); } private void endEdit() { valueText.setVisible(false); valueText.setText(""); valueText.removeFocusListener(this); } public void mouseDoubleClick(MouseEvent e) { } public void mouseDown(MouseEvent e) { int column = getSelectedColumn(e.x, e.y); if (column == -1) return; if (column == 1) { doEdit(); } } private int getSelectedColumn(int x, int y) { int columnToEdit = -1; int columns = table.getColumnCount(); TableItem tableItem = getSelectedTableItem(); if (tableItem == null) return -1; for (int i = 0; i < columns; i++) { Rectangle bounds = tableItem.getBounds(i); if (bounds.contains(x, y)) { columnToEdit = i; break; } } return columnToEdit; } private TableItem getSelectedTableItem() { TableItem[] selection = table.getSelection(); if (selection.length > 0) { return selection[0]; } else { return null; } } public void mouseUp(MouseEvent e) { } public void widgetDefaultSelected(SelectionEvent e) { } private void applyValue() { TableItem item = getSelectedTableItem(); if (item == null) return; item.setText(1, valueText.getText()); GenericElement element = (GenericElement)item.getData(); if (element == null) return; element.setValue(valueText.getText()); } public void widgetSelected(SelectionEvent e) { if (e.widget == table) { if (e.detail == SWT.CHECK && e.item instanceof TableItem) { handleTableItemCheck((TableItem)e.item); } } } private void handleTableItemCheck(TableItem item) { if (item.getChecked()) { addGenericElement(item); } else { removeGenericElement(item); } table.setSelection(item); } public void setVisible(boolean visible) { label.setVisible(visible); table.setVisible(visible); } public void focusGained(FocusEvent e) { } public void focusLost(FocusEvent e) { if (e.widget == valueText) { applyValue(); endEdit(); } } } }