/* * JBoss, Home of Professional Open Source. * * See the LEGAL.txt file distributed with this work for information regarding copyright ownership and licensing. * * See the AUTHORS.txt file distributed with this work for a full listing of individual contributors. */ package org.teiid.designer.ui.properties.extension; import static org.teiid.designer.extension.ExtensionPlugin.Util; import static org.teiid.designer.ui.UiConstants.PLUGIN_ID; import java.util.Collection; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.emf.ecore.EObject; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ComboBoxCellEditor; import org.eclipse.jface.viewers.ICellEditorValidator; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IFileEditorInput; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.part.FileEditorInput; import org.eclipse.ui.views.properties.PropertyDescriptor; import org.teiid.core.designer.HashCodeUtil; import org.teiid.core.designer.properties.PropertyDefinition; import org.teiid.core.designer.util.CoreArgCheck; import org.teiid.core.designer.util.CoreStringUtil; import org.teiid.designer.core.workspace.ModelResource; import org.teiid.designer.core.workspace.ModelUtil; import org.teiid.designer.core.workspace.ModelWorkspaceException; import org.teiid.designer.extension.ExtensionPlugin; import org.teiid.designer.extension.definition.ModelExtensionAssistant; import org.teiid.designer.extension.definition.ModelObjectExtensionAssistant; import org.teiid.designer.extension.properties.ModelExtensionPropertyDefinition; import org.teiid.designer.ui.editors.ModelEditorManager; /** * * * @since 8.0 */ public class ModelExtensionPropertyDescriptor extends PropertyDescriptor implements Comparable<ModelExtensionPropertyDescriptor> { // TODO see references to ExtensionPropertyDescriptor to see if references to this class is needed??? private static ICellEditorValidator createValidator( final ModelExtensionPropertyDefinition propDefn ) { return new ICellEditorValidator() { /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.ICellEditorValidator#isValid(java.lang.Object) */ @Override public String isValid( Object value ) { return propDefn.isValidValue((String)value); } }; } private final EObject eObject; private final ILabelProvider labelProvider; private final ModelExtensionPropertyDefinition propDefn; /** * Constructor * @param eObject the supplied EObject * @param propDefn the model extension property definition */ public ModelExtensionPropertyDescriptor( EObject eObject, ModelExtensionPropertyDefinition propDefn ) { super(propDefn.getId(), (CoreStringUtil.isEmpty(propDefn.getDisplayName()) ? propDefn.getId() : propDefn.getNamespaceProvider() .getNamespacePrefix() + ':' + propDefn.getDisplayName())); CoreArgCheck.isNotNull(eObject, "eObject is null"); //$NON-NLS-1$ this.eObject = eObject; this.propDefn = propDefn; this.labelProvider = new ModelExtensionDescriptorLabelProvider(); setCategory(Messages.modelExtensionPropertyCategory); setDescription(this.propDefn.getDescription()); setLabelProvider(this.labelProvider); } /** * {@inheritDoc} * * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo( ModelExtensionPropertyDescriptor thatDescriptor ) { return this.propDefn.getId().compareTo(thatDescriptor.propDefn.getId()); } /** * {@inheritDoc} * * @see org.eclipse.ui.views.properties.IPropertyDescriptor#createPropertyEditor(org.eclipse.swt.widgets.Composite) */ @Override public CellEditor createPropertyEditor( Composite parent ) { CellEditor editor = null; // a null cell editor is a readonly editor ModelResource modelResource = null; try { modelResource = ModelUtil.getModifiableModel(this.eObject); if (modelResource == null || (!this.propDefn.isModifiable())) { return null; } } catch (ModelWorkspaceException e) { Util.log(e); return null; } // editor must be open to edit property IFile file = (IFile)modelResource.getResource(); // workspace file not found if (file == null) { // really shouldn't happen if we have a model resource Util.log(IStatus.ERROR, NLS.bind(Messages.workspaceFileNotFound, modelResource.getItemName())); return null; } // if model editor is not open ask user if they want it opened try { IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); IFileEditorInput fileInput = new FileEditorInput(file); IEditorPart modelEditor = page.findEditor(fileInput); if (modelEditor == null) { if (!ModelEditorManager.autoOpen(window.getShell(), this.eObject, true)) { // user chose not to open editor return null; } } } catch (Exception e) { Util.log(e); return null; } // editor is open so create editable cell editor final String[] allowedValues = this.propDefn.getAllowedValues(); // Special case of udfJarPath property if(this.propDefn.getId().equalsIgnoreCase("function:udfJarPath") || //$NON-NLS-1$ this.propDefn.getId().equalsIgnoreCase("relational:udfJarPath")) { //$NON-NLS-1$ return new UdfJarDialogCellEditor(parent,this.eObject); } // use combobox editor if there are allowed values if ((allowedValues != null) && (allowedValues.length != 0)) { editor = new ComboBoxCellEditor(parent, allowedValues, SWT.READ_ONLY); } else { // use text editor since there are not known values editor = new TextCellEditor(parent); editor.setValidator(createValidator(this.propDefn)); // mask value if needed if (this.propDefn.isMasked()) { ((Text)editor.getControl()).setEchoChar('*'); } // TODO need to find a way to clear the error message (status bar) after editor is deactivated } return editor; } /** * {@inheritDoc} * * @see org.eclipse.ui.views.properties.PropertyDescriptor#getDescription() */ @Override public String getDescription() { return this.propDefn.getDescription(); } /** * {@inheritDoc} * * @see org.eclipse.ui.views.properties.PropertyDescriptor#getId() */ @Override public Object getId() { return this; } /** * Get the Property Defn Id * @return propDefn ID */ public String getPropDefnId() { return this.propDefn.getId(); } ModelObjectExtensionAssistant getModelExtensionAssistant( String propId ) { Collection<ModelExtensionAssistant> assistants = ExtensionPlugin.getInstance() .getRegistry() .getModelExtensionAssistants(this.eObject.getClass() .getName()); // no assistants found that have properties defined for the model object type if (assistants.isEmpty()) { log(new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.modelExtensionAssistantNotFound, propId))); return null; } // find the assistant for the property for (ModelExtensionAssistant assistant : assistants) { if (ModelExtensionPropertyDefinition.Utils.isExtensionPropertyId(propId, assistant.getModelExtensionDefinition())) { return ((assistant instanceof ModelObjectExtensionAssistant) ? (ModelObjectExtensionAssistant)assistant : null); } } log(new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.modelExtensionAssistantNotFound, propId))); return null; } /** * @return the model object (never <code>null</code>) */ protected EObject getModelObject() { return this.eObject; } /** * @return the property definition (never <code>null</code>) */ protected ModelExtensionPropertyDefinition getPropertyDefinition() { return this.propDefn; } Object getPropertyValue() { String propId = this.propDefn.getId(); ModelObjectExtensionAssistant assistant = getModelExtensionAssistant(propId); if (assistant != null) { try { String value = assistant.getPropertyValue(this.eObject, propId); String[] allowedValues = propDefn.getAllowedValues(); boolean hasAllowedValues = ((allowedValues != null) && (allowedValues.length != 0)); // no value if (CoreStringUtil.isEmpty(value)) { // prop defn has allowed values but since we must return an int because there are allowed values return -1 // which will clear selection in comboboxcelleditor if (hasAllowedValues) { return -1; } // ensure value is empty string not null as TextCellEditor requires non-null value value = CoreStringUtil.Constants.EMPTY_STRING; } else if (hasAllowedValues) { // a value that is an allowed values must be converted to the index for (int i = 0; i < allowedValues.length; ++i) { if (allowedValues[i].equalsIgnoreCase(value)) { return i; } } // current value is not a current allowed value so just clear comboboxcelleditor selection log(new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.valueIsNotAnAllowedValue, value, propId))); return -1; } return value; } catch (Exception e) { String msg = NLS.bind(Messages.errorObtainingPropertyFromAssistant, propId, assistant.getClass().getName()); log(new Status(IStatus.ERROR, PLUGIN_ID, msg, e)); } } log(new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.unexpectedPropertySourceId, propId))); return CoreStringUtil.Constants.EMPTY_STRING; } void log( IStatus status ) { ExtensionPlugin.getInstance().getLog().log(status); } void setPropertyValue( Object value ) { String propId = this.propDefn.getId(); ModelObjectExtensionAssistant assistant = getModelExtensionAssistant(propId); if (assistant != null) { // if integer, value must be an index to an allowed value so convert to the value at that index if (value instanceof Integer) { int index = (Integer)value; String[] allowedValues = propDefn.getAllowedValues(); // make sure index makes sense if ((index < 0) || (allowedValues == null) || (allowedValues.length == 0) || (index > (allowedValues.length - 1))) { // don't return a value value = CoreStringUtil.Constants.EMPTY_STRING; } else { value = allowedValues[index]; } } if (value instanceof String) { try { assistant.setPropertyValue(this.eObject, propId, (String)value); } catch (Exception e) { String msg = NLS.bind(Messages.errorObtainingPropertyFromAssistant, propId, assistant.getClass().getName()); log(new Status(IStatus.ERROR, PLUGIN_ID, msg, e)); } } else { log(new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.unexpectedPropertyValueType, propId))); } } else { log(new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.unexpectedPropertySourceId, propId.getClass().getName()))); } } /** * Used only for the value column in the properties view. */ protected class ModelExtensionDescriptorLabelProvider extends LabelProvider { /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object) */ @Override public Image getImage( Object element ) { PropertyDefinition propDefn = getPropertyDefinition(); Object value = getPropertyValue(); if (value instanceof String) { String errorMsg = propDefn.isValidValue((String)value); // add error icon if (!CoreStringUtil.isEmpty(errorMsg)) { return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK); } String stringValue = (String)value; String defaultValue = propDefn.getDefaultValue(); if ((CoreStringUtil.isEmpty(stringValue) && CoreStringUtil.isEmpty(defaultValue)) || CoreStringUtil.equals(stringValue, defaultValue)) { return null; } // add icon to show value is different than the default return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE); } // integer values are indexes into allowed values collection if (value instanceof Integer) { // if no value set to empty string String stringValue = CoreStringUtil.Constants.EMPTY_STRING; if (((Integer)value).intValue() == -1) { // error if no value and value is required if (propDefn.isRequired()) { return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJS_ERROR_TSK); } } else { stringValue = propDefn.getAllowedValues()[(Integer)value]; } if (!CoreStringUtil.valuesAreEqual(stringValue, propDefn.getDefaultValue())) { return PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FILE); } } return null; } /** * {@inheritDoc} * * @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object) */ @Override public String getText( Object element ) { if (getPropertyDefinition().isMasked()) { return "*****"; //$NON-NLS-1$ } // convert integer to string when allowed values if (element instanceof Integer) { String[] allowedValues = getPropertyDefinition().getAllowedValues(); if ((allowedValues != null) && (allowedValues.length != 0)) { if (((Integer)element).intValue() == -1) { return CoreStringUtil.Constants.EMPTY_STRING; } return allowedValues[(Integer)element]; } } return super.getText(element); } } /** * {@inheritDoc} * * @see java.lang.Object#toString() */ @Override public String toString() { return getDisplayName(); } /** * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if ( obj == null ) { return false; } if ( obj == this ) { return true; } // Instances must be of the same class if ( !obj.getClass().equals(this.getClass()) ) { return false; } final ModelExtensionPropertyDescriptor that = (ModelExtensionPropertyDescriptor)obj; // Check the PropertyDefns if ( !this.getPropertyDefinition().equals(that.getPropertyDefinition()) ) { return false; } // Check the ModelObjects if ( !this.getModelObject().equals(that.getModelObject()) ) { return false; } return true; } /** * @see java.lang.Object#hashCode() */ @Override public int hashCode() { int hc = 0; hc = HashCodeUtil.hashCode(hc, this.getPropertyDefinition()); hc = HashCodeUtil.hashCode(hc, this.getModelObject()); return hc; } }