Migration Guide for 0.5
This documents covers code changes that need to be made by Sapphire adopters as part of migrating
to 0.5 release. Only changes from the previous release are covered.
Table of Contents
- CompositeStatusFactory
- IModelElement
- LayeredListBindingImpl
- ListBindingImpl
- MasterDetailsEditorPage
- MasterDetailsEditorPagePart
- ModelElementList
- ModelElementListener
- ModelElementType
- ModelProperty
- ModelPropertyListener
- PropertyListeners
- SapphireActionHandler
- SapphireDiagramActionHandler
- SapphireEditor
- SapphireWizardPageListener
- Actuator
- Content Outline Node Image
- Diagram Drag-n-Drop
- Diagram Image
- Graphiti to GEF Transition
Before |
After |
factory.add( status );
|
factory.merge( status );
|
Before |
After |
element.getModelElementType();
|
element.type();
|
element.isPropertyEnabled( property );
|
element.enabled( property );
|
element.addListener( listener );
|
element.attach( listener );
|
element.addListener( listener, path );
|
element.attach( listener, path );
|
element.removeListener( listener );
|
element.detach( listener );
|
element.removeListener( listener, path );
|
element.detach( listener, path );
|
element.notifyPropertyChangeListeners( property );
|
element.refresh( property );
|
The list binding API has been improved to more efficiently support insertion into the middle of the list along with arbitrary
movement of existing list items.
Before |
After |
public class ExampleListBinding extends LayeredListBindingImpl
{
@Override
protected Resource createResource( Object obj )
{
...
}
@Override
protected Resource addUnderlyingObject( ModelElementType type )
{
...
}
@Override
public void swap( Resource x, Resource y )
{
...
}
...
}
|
public class ExampleListBinding extends LayeredListBindingImpl
{
@Override
protected Resource resource( Object obj )
{
...
}
@Override
protected Object insertUnderlyingObject( ModelElementType type, int position )
{
final Object obj = addUnderlyingObject( type );
move( resource( obj ), position );
return obj;
}
private Object addUnderlyingObject( ModelElementType type )
{
...
}
@Override
public void move( Resource resource, int position )
{
List<Resource> list = read();
int size = list.size();
if( position < 0 || position > size )
{
throw new IllegalArgumentException();
}
else
{
int oldPosition = list.indexOf( resource );
if( position < oldPosition )
{
for( int i = oldPosition; i >= position; i-- )
{
moveUp( list, resource );
}
}
else
{
for( int i = oldPosition; i <= position; i++ )
{
moveDown( list, resource );
}
}
}
}
private void moveUp( List<Resource> list, Resource resource )
{
int index = list.indexOf( resource );
if( index == -1 )
{
throw new IllegalArgumentException();
}
if( index > 0 )
{
Resource previous = list.get( index - 1 );
swap( resource, previous );
}
}
private void moveDown( List<Resource> list, Resource resource )
{
int index = list.indexOf( resource );
if( index == -1 )
{
throw new IllegalArgumentException();
}
if( index < list.size() - 1 )
{
Resource next = list.get( index + 1 );
swap( resource, next );
}
}
private void swap( Resource x, Resource y )
{
...
}
...
}
The above represents the quickest way to migrate an existing list binding, but is far from ideal. A better
solution would be to implement the new insertUnderlyingObject() and move() methods directly.
|
The list binding API has been improved to more efficiently support insertion into the middle of the list along with arbitrary
movement of existing list items.
Before |
After |
public class ExampleListBinding extends ListBindingImpl
{
@Override
public Resource add( ModelElementType type )
{
...
}
@Override
public void swap( Resource x, Resource y )
{
...
}
...
}
|
public class ExampleListBinding extends ListBindingImpl
{
@Override
public Resource insert( ModelElementType type, int position )
{
Resource resource = add( type );
move( resource, position );
return resource;
}
private Resource add( ModelElementType type )
{
...
}
@Override
public void move( Resource resource, int position )
{
List<Resource> list = read();
int size = list.size();
if( position < 0 || position > size )
{
throw new IllegalArgumentException();
}
else
{
int oldPosition = list.indexOf( resource );
if( position < oldPosition )
{
for( int i = oldPosition; i >= position; i-- )
{
moveUp( list, resource );
}
}
else
{
for( int i = oldPosition; i <= position; i++ )
{
moveDown( list, resource );
}
}
}
}
private void moveUp( List<Resource> list, Resource resource )
{
int index = list.indexOf( resource );
if( index == -1 )
{
throw new IllegalArgumentException();
}
if( index > 0 )
{
Resource previous = list.get( index - 1 );
swap( resource, previous );
}
}
private void moveDown( List<Resource> list, Resource resource )
{
int index = list.indexOf( resource );
if( index == -1 )
{
throw new IllegalArgumentException();
}
if( index < list.size() - 1 )
{
Resource next = list.get( index + 1 );
swap( resource, next );
}
}
private void swap( Resource x, Resource y )
{
...
}
...
}
The above represents the quickest way to migrate an existing list binding, but is far from ideal. A better
solution would be to implement the new insert() and move() methods directly.
|
Before |
After |
page.getContentTree();
|
page.outline();
|
Before |
After |
page.getContentTree();
|
page.outline();
|
Before |
After |
list.addNewElement( ExampleElementVariant.TYPE );
|
list.insert( ExampleElementVariant.TYPE );
|
list.addNewElement();
|
list.insert();
|
Before |
After |
public ExampleListener extends ModelElementListener
{
@Override
public void propertyChanged( ModelPropertyChangeEvent event )
{
...
}
}
|
public ExampleListener extends FilteredListener<PropertyEvent>
{
@Override
protected void handleTypedEvent( PropertyEvent event )
{
...
}
}
|
public ExampleListener extends ModelElementListener
{
@Override
public void validationStateChanged( final ValidationStateChangeEvent event )
{
...
}
}
|
public ExampleListener extends FilteredListener<ElementValidationEvent>
{
@Override
protected void handleTypedEvent( ElementValidationEvent event )
{
...
}
}
|
public ExampleListener extends ModelElementListener
{
@Override
public void handleElementDisposedEvent( final ModelElementDisposedEvent event )
{
...
}
}
|
public ExampleListener extends FilteredListener<ElementDisposeEvent>
{
@Override
protected void handleTypedEvent( ElementDisposeEvent event )
{
...
}
}
|
Before |
After |
ModelElementType.getModelElementType( ... )
|
ModelElementType.read( ... )
|
type.getProperties()
|
type.properties()
|
type.getProperty( ... )
|
type.property( ... )
|
Before |
After |
property.addListener( ... )
|
property.attach( ... )
|
property.getListeners()
|
No replacement has been provided. This method was an internal implementation detail. Any adopter with a dependency
on this method is urged to post details to Sapphire Adopter Forum.
|
Before |
After |
public ExampleListener extends ModelPropertyListener
{
@Override
public void public void handlePropertyChangedEvent( ModelPropertyChangeEvent event )
{
...
}
}
|
public ExampleListener extends FilteredListener<PropertyEvent>
{
@Override
protected void handleTypedEvent( PropertyEvent event )
{
...
}
}
The above is the most direct migration target, but in many cases more efficient results can be achieved by filtering
on PropertyContentEvent instead.
public ExampleListener extends FilteredListener<PropertyContentEvent>
{
@Override
protected void handleTypedEvent( PropertyContentEvent event )
{
...
}
}
The other subclasses of PropertyEvent are PropertyEnablementEvent and PropertyValidationEvent.
|
Before |
After |
@PropertyListeners( ... )
|
@Listeners( ... )
|
Before |
After |
import org.eclipse.sapphire.ui.def.ISapphireActionHandlerDef;
|
import org.eclipse.sapphire.ui.def.ActionHandlerDef;
|
public class CustomActionHandler extends SapphireActionHandler
{
@Override
public void init( SapphireAction action, ISapphireActionHandlerDef def )
{
super.init( action, def );
...
}
...
}
|
public class CustomActionHandler extends SapphireActionHandler
{
@Override
public void init( SapphireAction action, ActionHandlerDef def )
{
super.init( action, def );
...
}
...
}
|
Before |
After |
public class ExampleActionHandler extends SapphireDiagramActionHandler
{
@Override
public boolean canExecute( Object obj )
{
...
}
...
}
|
public class ExampleActionHandler extends SapphireActionHandler
{
...
}
|
Before |
After |
setPageId( editorPage, editorPageId, editorPagePart )
|
Remove method call. It is no longer necessary.
|
The wizard page part has been converted to use common listener framework.
Before |
After |
public class ExampleListener extends SapphireWizardPageListener
{
@Override
public void handleShowPageEvent( SapphirePartEvent event )
{
...
}
}
|
public class ExampleListener extends FilteredListener<VisibilityChangedEvent>
{
@Override
protected void handleTypedEvent( VisibilityChangedEvent event )
{
if( ( (SapphireWizardPagePart) event.part() ).isVisible() )
{
...
}
}
}
|
public class ExampleListener extends SapphireWizardPageListener
{
@Override
public void handleHidePageEvent( SapphirePartEvent event )
{
...
}
}
|
public class ExampleListener extends FilteredListener<VisibilityChangedEvent>
{
@Override
protected void handleTypedEvent( VisibilityChangedEvent event )
{
if( ! ( (SapphireWizardPagePart) event.part() ).isVisible() )
{
...
}
}
}
|
part.addListener( listener )
|
part.attach( listener )
|
part.removeListener( listener )
|
part.dettach( listener )
|
The action link facility in sdef language has been generalized to support other presentations. In the
process it was renamed as actuator.
Before |
After |
<action-link>
<action-id>Sapphire.Add</action-id>
<label>add a contact</label>
</action-link>
|
<actuator>
<action-id>Sapphire.Add</action-id>
<label>add a contact</label>
</actuator>
|
<action-link>
<action-id>Sapphire.Add</action-id>
<label>add a contact</label>
<show-image/>
</action-link>
|
<actuator>
<action-id>Sapphire.Add</action-id>
<label>add a contact</label>
<show-image>true</show-image>
</actuator>
|
Scope: *.sdef
Search: (?s)<action-link>(.*?)<show-image/>(.*?)</action-link>
Replace: <actuator>\1<show-image>true</show-image>\2</actuator>
Scope: *.sdef
Search: (?s)<action-link>(.*?)</action-link>
Replace: <actuator>\1</actuator>
Prior to advent of Sapphire Expression Language, sdef language included the "use-model-element-image" switch
as a way to indicate to the system that content outline node's image should be the same as the image for the
associated model element. With advent of EL, the special switch is no longer necessary as an expression can be used
to capture the same semantics.
Before |
After |
<use-model-element-image/>
|
<image>${ Image() }</image>
|
Scope: *.sdef
Search: <use-model-element-image[ ]*/>
Replace: <image>\${ Image() }</image>
Scope: *.sdef
Search: <use-model-element-image>[ ]*</use-model-element-image>
Replace: <image>\${ Image() }</image>
Drag-n-drop support in the diagram editor has been reworked to use service mechanism instead of action mechanism.
Before |
After |
public class ExampleDragAndDropActionHandler extends SapphireDiagramActionHandler
{
@Override
public boolean canExecute( Object obj )
{
...
}
@Override
protected Object run( SapphireRenderingContext context )
{
DiagramRenderingContext ctx = (DiagramRenderingContext) context;
Object obj = ctx.getObject();
...
}
}
|
public class ExampleDragAndDropService extends DragAndDropService
{
@Override
public boolean droppable( DropContext context )
{
Object obj = context.object();
...
}
@Override
public void drop( DropContext context )
{
Object obj = context.object();
...
}
}
|
<diagram-page>
<action-handler>
<action>Sapphire.Drop</action>
<impl>ExampleDragAndDropActionHandler</impl>
</action-handler>
</diagram-page>
|
<diagram-page>
<service>
<implementation>ExampleDragAndDropService</implementation>
</service>
</diagram-page>
|
Image specifications inside diagram parts are now consistent with the rest of the sdef.
Images are now referenced at the point of use, rather than defined separately and then referenced by id.
Before |
After |
<image-decorator>
<id>defaultIndicator</id>
<path>icons/default-indicator.png</path>
</image-decorator>
|
Remove, path will be specified at the point of use.
|
<image-decorator>
<id>defaultIndicator</id>
<decorator-placement>image</decorator-placement>
<horizontal-align>center</horizontal-align>
<vertical-align>top</vertical-align>
</image-decorator>
|
<image-decorator>
<path>icons/default-indicator.png</path>
<decorator-placement>image</decorator-placement>
<horizontal-align>center</horizontal-align>
<vertical-align>top</vertical-align>
</image-decorator>
|
<tool-palette-image>
<id>flowPaletteImage</id>
<path>icons/control-flow-16.png</path>
</tool-palette-image>
|
<tool-palette-image>icons/control-flow-16.png</tool-palette-image>
|
<image>
<id>routerIcon</id>
<placement>top</placement>
<possible>
<id>routerIcon</id>
<path>icons/node-router.png</path>
</possible>
</image>
|
<image>
<path>icons/node-router.png</path>
<placement>top</placement>
</image>
|
The Graphiti-based diagram presentation (introduced in 0.4 release) has been replaced with a presentation
written directly on top of GEF. This has significantly reduced Sapphire's dependencies and enabled diagram
support to more tightly integrate with the rest of Sapphire.
Before |
After |
import org.eclipse.sapphire.ui.gef.diagram.editor.[etc];
|
import org.eclipse.sapphire.ui.swt.gef.[etc];
|
page = new SapphireDiagramEditor( model, path );
addPage( 0, page, SapphireDiagramEditorFactory.createEditorInput( file ) );
|
page = new SapphireDiagramEditor( this, model, path );
addPage( 0, page );
|