/**************************************************************************
* ERA - Eclipse Requirements Analysis
* ==============================================
* Copyright (C) 2009-2013 by Georg Blaschke, Christoph P. Neumann
* and Bernd Haberstumpf (http://era.origo.ethz.ch)
**************************************************************************
* Licensed under the Eclipse Public License - v 1.0 (the "License");
* you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.eclipse.org/org/documents/epl-v10.html
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**************************************************************************
*/
package era.foss.objecteditor.specobject;
import org.eclipse.core.databinding.Binding;
import org.eclipse.core.databinding.DataBindingContext;
import org.eclipse.core.databinding.observable.ChangeEvent;
import org.eclipse.core.databinding.observable.IChangeListener;
import org.eclipse.emf.common.command.Command;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.util.Diagnostician;
import org.eclipse.emf.edit.command.DeleteCommand;
import org.eclipse.emf.edit.domain.EditingDomain;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.fieldassist.ControlDecoration;
import org.eclipse.jface.fieldassist.FieldDecoration;
import org.eclipse.jface.fieldassist.FieldDecorationRegistry;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import era.foss.erf.AttributeValue;
import era.foss.erf.SpecObject;
import era.foss.erf.ViewElement;
import era.foss.ui.contrib.EraImages;
/**
* The Class AbstractAttributeDefinitionComposite.
*/
public abstract class AbstractAttributeDefinitionComposite extends Composite {
/** color for default values. */
final static int COLOR_DEFAULT_VALUE = SWT.COLOR_INFO_BACKGROUND;
/** The view element to show which refers to a AttributeDefifinition. */
final ViewElement viewElement;
/** Create one data binding context for all Elements. */
static final DataBindingContext dbc = new DataBindingContext();
/** binding of the GUI element to the model element. */
Binding binding;
/** The control. */
private Control control;
/** The error decoration. */
private ControlDecoration errorDecoration;
/** The attribute value. */
protected AttributeValue attributeValue;
/** The editing domain. */
protected EditingDomain editingDomain;
/** The spec object. */
protected SpecObject specObject;
/** The change listener. */
private IChangeListener changeListener;
/**
* Instantiates a new abstract attribute definition composite.
*
* @param parent the parent
* @param viewElement the view element
*/
public AbstractAttributeDefinitionComposite( Composite parent, ViewElement viewElement ) {
super( parent, SWT.NONE );
this.setLayout( new FillLayout() );
this.viewElement = viewElement;
this.control = createControl();
// create a change listener triggering the validation
this.changeListener = new IChangeListener() {
@Override
public void handleChange( ChangeEvent event ) {
AbstractAttributeDefinitionComposite.this.validate();
}
};
// set up decoration for showing erroneous validation
errorDecoration = new ControlDecoration( this.control, SWT.RIGHT | SWT.TOP );
errorDecoration.hide();
FieldDecoration fieldDecoration = FieldDecorationRegistry.getDefault()
.getFieldDecoration( FieldDecorationRegistry.DEC_ERROR );
errorDecoration.setImage( fieldDecoration.getImage() );
// add menu
createContextMenu();
}
/**
* Create the control according to the respective AttributeDefinition.
*
* @return the control
*/
abstract public Control createControl();
/**
* Get the control actually representing the AttributeDefinition.
*
* @return the control
*/
public abstract Control getControl();
/**
* Bind the AttributeValue to the control
*
* @param specObject SpecObject holding this attribute
* @param attributeValue AttributeValue to bind (may also be null)
* @param editingDomain the editing Domain
*/
public abstract void doBind( SpecObject specObject, AttributeValue attributeValue, EditingDomain editingDomain );
/**
* Return the view element associated with this GUI element.
*
* @return the view element associated with this GUI element
*/
public ViewElement getViewElement() {
return viewElement;
}
/**
* Bind the GUI element to the model element. This has to be implemented be subclasses.
*
* <strong>Subclasses have to to call this method in case the ovveride it.</strong>
*
* @param specObject the spec object
* @param attributeValue the attribute value
* @param editingDomain the editing domain
*/
public void bind( SpecObject specObject, AttributeValue attributeValue, EditingDomain editingDomain ) {
this.unbind();
this.specObject = specObject;
this.attributeValue = attributeValue;
this.editingDomain = editingDomain;
this.doBind( specObject, attributeValue, editingDomain );
this.setupValidation();
}
/**
* Unbind the GUI element from the model element.
*
* <strong>Subclasses have to to call this method in case the ovveride it.</strong>
*/
public void unbind() {
if( this.binding != null ) {
removeValidation();
dbc.removeBinding( binding );
binding.dispose();
binding = null;
attributeValue = null;
}
}
/**
* Setup validation
* <ol>
* <li>Update validation status
* <li>Add listener to invoke validation on any changes
* </ol>
*/
private void setupValidation() {
this.validate();
if( binding != null && binding.isDisposed() == false ) {
binding.getModel().addChangeListener( this.changeListener );
}
}
/**
* Tear down validation
* <ol>
* <li>Remove change listener
* </ol>
*/
private void removeValidation() {
this.validate();
if( binding != null && binding.isDisposed() == false && this.changeListener != null ) {
binding.getModel().removeChangeListener( this.changeListener );
}
}
/**
* Validate the value and adapt decoration
*/
private void validate() {
if( attributeValue != null ) {
Diagnostic diagnostic = Diagnostician.INSTANCE.validate( attributeValue );
if( diagnostic.getSeverity() == Diagnostic.ERROR ) {
errorDecoration.show();
} else {
errorDecoration.hide();
}
} else {
errorDecoration.hide();
}
}
/**
* Creates the context menu for all kind of AttributeDefinitions
*/
protected void createContextMenu() {
/**
* Action for removing a value from a spec object
*
* From the point of the user this will be seen as setting a value to it respective default value
*/
final class RemoveValueAction extends Action {
public RemoveValueAction() {
this.setText( "Restore default value" );
this.setImageDescriptor( EraImages.getImageDescriptor( EraImages.IMG_DEFAULT_VALUE ) );
}
@Override
public void run() {
AttributeValue attributeValueLocal = attributeValue;
unbind();
Command deleteCommand = new DeleteCommand( editingDomain, new StructuredSelection(
attributeValueLocal ).toList() );
editingDomain.getCommandStack().execute( deleteCommand );
}
}
final MenuManager menuMgr = new MenuManager();
menuMgr.setRemoveAllWhenShown( true );
menuMgr.addMenuListener( new IMenuListener() {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager)
*/
public void menuAboutToShow( IMenuManager manager ) {
SpecObjectHandler.createCommonMenuItems( manager, editingDomain, specObject );
manager.add( new Separator() );
AbstractAttributeDefinitionComposite.this.menuAboutToShow( manager );
manager.add( new Separator() );
if( attributeValue != null ) {
manager.add( new RemoveValueAction() );
}
manager.add( new Separator() );
}
} );
// register menu at the table viewer
control.setMenu( menuMgr.createContextMenu( control ) );
}
/**
* Menu about to show.
*
* @param manager the manager
*/
protected void menuAboutToShow( IMenuManager manager ) {
}
}