/****************************************************************************** * Copyright (c) 2016 Oracle and Liferay * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Konstantin Komissarchik - initial implementation and ongoing maintenance * Ling Hao - [329114] rewrite context help binding feature * Gregory Amerson - [372816] Provide adapt mechanism for SapphirePart * Gregory Amerson - [373614] Suppport AdapterService in SapphirePart * Gregory Amerson - [346172] Support zoom, print and save as image actions ******************************************************************************/ package org.eclipse.sapphire.ui; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.help.IContext; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.sapphire.DisposeEvent; import org.eclipse.sapphire.Element; import org.eclipse.sapphire.ElementImpl; import org.eclipse.sapphire.ElementType; import org.eclipse.sapphire.Event; import org.eclipse.sapphire.FilteredListener; import org.eclipse.sapphire.ImageData; import org.eclipse.sapphire.ImpliedElementProperty; import org.eclipse.sapphire.Listener; import org.eclipse.sapphire.ListenerContext; import org.eclipse.sapphire.LocalizableText; import org.eclipse.sapphire.LoggingService; import org.eclipse.sapphire.MasterConversionService; import org.eclipse.sapphire.MasterVersionCompatibilityService; import org.eclipse.sapphire.Property; import org.eclipse.sapphire.PropertyContentEvent; import org.eclipse.sapphire.PropertyDef; import org.eclipse.sapphire.Sapphire; import org.eclipse.sapphire.Text; import org.eclipse.sapphire.java.JavaType; import org.eclipse.sapphire.modeling.ModelPath; import org.eclipse.sapphire.modeling.Status; import org.eclipse.sapphire.modeling.el.FailSafeFunction; import org.eclipse.sapphire.modeling.el.Function; import org.eclipse.sapphire.modeling.el.FunctionContext; import org.eclipse.sapphire.modeling.el.FunctionResult; import org.eclipse.sapphire.modeling.el.Literal; import org.eclipse.sapphire.services.Service; import org.eclipse.sapphire.ui.def.ISapphireParam; import org.eclipse.sapphire.ui.def.ISapphirePartListenerDef; import org.eclipse.sapphire.ui.def.PartDef; import org.eclipse.sapphire.ui.forms.ActuatorDef; import org.eclipse.sapphire.ui.forms.ActuatorPart; import org.eclipse.sapphire.ui.forms.CompositeDef; import org.eclipse.sapphire.ui.forms.CompositePart; import org.eclipse.sapphire.ui.forms.CustomFormComponentDef; import org.eclipse.sapphire.ui.forms.DetailSectionDef; import org.eclipse.sapphire.ui.forms.DetailSectionPart; import org.eclipse.sapphire.ui.forms.DialogDef; import org.eclipse.sapphire.ui.forms.DialogPart; import org.eclipse.sapphire.ui.forms.FormComponentRef; import org.eclipse.sapphire.ui.forms.FormDef; import org.eclipse.sapphire.ui.forms.FormEditorPageDef; import org.eclipse.sapphire.ui.forms.FormEditorPagePart; import org.eclipse.sapphire.ui.forms.FormPart; import org.eclipse.sapphire.ui.forms.GroupDef; import org.eclipse.sapphire.ui.forms.GroupPart; import org.eclipse.sapphire.ui.forms.HtmlPanelDef; import org.eclipse.sapphire.ui.forms.HtmlPanelPart; import org.eclipse.sapphire.ui.forms.LineSeparatorDef; import org.eclipse.sapphire.ui.forms.LineSeparatorPart; import org.eclipse.sapphire.ui.forms.MasterDetailsEditorPageDef; import org.eclipse.sapphire.ui.forms.MasterDetailsEditorPagePart; import org.eclipse.sapphire.ui.forms.PropertyEditorDef; import org.eclipse.sapphire.ui.forms.PropertyEditorPart; import org.eclipse.sapphire.ui.forms.SectionDef; import org.eclipse.sapphire.ui.forms.SectionPart; import org.eclipse.sapphire.ui.forms.SectionRef; import org.eclipse.sapphire.ui.forms.SpacerDef; import org.eclipse.sapphire.ui.forms.SpacerPart; import org.eclipse.sapphire.ui.forms.SplitFormDef; import org.eclipse.sapphire.ui.forms.SplitFormPart; import org.eclipse.sapphire.ui.forms.SplitFormSectionDef; import org.eclipse.sapphire.ui.forms.SplitFormSectionPart; import org.eclipse.sapphire.ui.forms.StaticTextFieldDef; import org.eclipse.sapphire.ui.forms.StaticTextFieldPart; import org.eclipse.sapphire.ui.forms.TabGroupDef; import org.eclipse.sapphire.ui.forms.TabGroupPart; import org.eclipse.sapphire.ui.forms.TextDef; import org.eclipse.sapphire.ui.forms.TextPart; import org.eclipse.sapphire.ui.forms.WithDef; import org.eclipse.sapphire.ui.forms.WithImpliedPart; import org.eclipse.sapphire.ui.forms.WithPart; import org.eclipse.sapphire.ui.forms.WizardPageDef; import org.eclipse.sapphire.ui.forms.WizardPagePart; import org.eclipse.sapphire.ui.forms.swt.SwtResourceCache; import org.eclipse.sapphire.ui.forms.swt.SwtUtil; import org.eclipse.sapphire.ui.internal.PartServiceContext; import org.eclipse.swt.widgets.Display; /** * @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a> * @author <a href="mailto:ling.hao@oracle.com">Ling Hao</a> * @author <a href="mailto:gregory.amerson@liferay.com">Gregory Amerson</a> */ public abstract class SapphirePart implements ISapphirePart { @Text( "Failed while instantiating {0} class." ) private static LocalizableText failedToInstantiate; @Text( "Class {0} does not extend the required Listener class." ) private static LocalizableText doesNotExtend; @Text( "Could not resolve form part include \"{0}\"." ) private static LocalizableText couldNotResolveInclude; @Text( "Could not resolve section \"{0}\"." ) private static LocalizableText couldNotResolveSection; static { LocalizableText.init( SapphirePart.class ); } private ISapphirePart parent; private Element modelElement; protected PartDef definition; protected Map<String,String> params; private Status validation; private ListenerContext listeners; private Set<SapphirePartListener> listenersDeprecated; private SwtResourceCache imageCache; private Map<String,SapphireActionGroup> actions; private PartServiceContext serviceContext; private FunctionResult visibilityFunctionResult; private boolean visibilityFunctionInitializing; private boolean initialized; private boolean disposed; public final boolean initialized() { return this.initialized; } public final void init( final ISapphirePart parent, final Element modelElement, final PartDef definition, final Map<String,String> params ) { this.parent = parent; this.definition = definition; this.params = params; if( modelElement == null ) { throw new IllegalArgumentException(); } this.modelElement = modelElement; } public final void initialize() { this.listeners = new ListenerContext( ( (ElementImpl) this.modelElement ).queue() ); for( ISapphirePartListenerDef listenerDefinition : this.definition.getListeners() ) { final JavaType listenerClass = listenerDefinition.getListenerClass().target(); if( listenerClass != null ) { Object listener = null; try { listener = ( (Class<?>) listenerClass.artifact() ).newInstance(); } catch( Exception e ) { final String msg = failedToInstantiate.format( listenerClass.name() ); Sapphire.service( LoggingService.class ).logError( msg, e ); } if( listener != null ) { if( listener instanceof Listener ) { attach( (Listener) listener ); } else { final String msg = doesNotExtend.format( listenerClass.name() ); Sapphire.service( LoggingService.class ).logError( msg ); } } } } init(); this.initialized = true; broadcast( new PartInitializationEvent( this ) ); } protected void init() { // The default implement doesn't do anything. } public final FunctionResult initExpression( final Function function, final Class<?> expectedType, final Function defaultValue ) { return initExpression( getLocalModelElement(), function, expectedType, defaultValue, null ); } public final FunctionResult initExpression( final Function function, final Class<?> expectedType, final Function defaultValue, final Runnable refreshOp ) { return initExpression( getLocalModelElement(), function, expectedType, defaultValue, refreshOp ); } public final FunctionResult initExpression( final Element element, final Function function, final Class<?> expectedType, final Function defaultValue ) { return initExpression( function, expectedType, defaultValue, null ); } public final FunctionResult initExpression( final Element element, final Function function, final Class<?> expectedType, final Function defaultValue, final Runnable refreshOp ) { Function f = ( function == null ? Literal.NULL : function ); f = FailSafeFunction.create( f, Literal.create( expectedType ), defaultValue ); final FunctionResult fr = f.evaluate( new PartFunctionContext( this, element ) ); if( refreshOp != null ) { fr.attach ( new Listener() { @Override public void handle( final Event event ) { final Runnable notifyOfUpdateOperation = new Runnable() { public void run() { if( ! disposed() && ! getLocalModelElement().disposed() ) { refreshOp.run(); } } }; Display.getDefault().syncExec( notifyOfUpdateOperation ); } } ); } return fr; } protected Function initVisibleWhenFunction() { return this.definition.getVisibleWhen().content(); } protected static final Function createVersionCompatibleFunction( final Property property ) { if( property != null ) { final MasterVersionCompatibilityService service = property.service( MasterVersionCompatibilityService.class ); final Function function = new Function() { @Override public String name() { return "VersionCompatible"; } @Override public FunctionResult evaluate( final FunctionContext context ) { return new FunctionResult( this, context ) { private Listener serviceListener; private Listener propertyListener; @Override protected void init() { this.serviceListener = new Listener() { @Override public void handle( final Event event ) { refresh(); } }; service.attach( this.serviceListener ); this.propertyListener = new FilteredListener<PropertyContentEvent>() { @Override protected void handleTypedEvent( final PropertyContentEvent event ) { refresh(); } }; if( property.definition() instanceof ImpliedElementProperty ) { property.element().attach( this.propertyListener, property.name() + "/*" ); } else { property.element().attach( this.propertyListener, property.name() ); } } @Override protected Object evaluate() { return service.compatible() || ! property.empty(); } @Override public void dispose() { super.dispose(); service.detach( this.serviceListener ); if( property.definition() instanceof ImpliedElementProperty ) { property.element().detach( this.propertyListener, property.name() + "/*" ); } else { property.element().detach( this.propertyListener, property.name() ); } } }; } }; function.init(); return function; } return null; } public PartDef definition() { return this.definition; } public ISapphirePart parent() { return this.parent; } @SuppressWarnings( "unchecked" ) public final <T> T nearest( final Class<T> partType ) { if( partType.isAssignableFrom( getClass() ) ) { return (T) this; } else { if( this.parent != null ) { return this.parent.nearest( partType ); } else { return null; } } } public final Element getModelElement() { return this.modelElement; } public Element getLocalModelElement() { return this.modelElement; } public final Map<String,String> getParams() { return Collections.unmodifiableMap( this.params ); } public final Status validation() { if( this.validation == null ) { refreshValidation(); } return this.validation; } protected Status computeValidation() { return Status.createOkStatus(); } protected final void refreshValidation() { if( Display.getCurrent() == null ) { Display.getDefault().asyncExec ( new Runnable() { public void run() { refreshValidation(); } } ); return; } final Status newValidationState = computeValidation(); if( newValidationState == null ) { throw new IllegalStateException(); } if( this.validation == null ) { this.validation = newValidationState; } else if( ! this.validation.equals( newValidationState ) ) { this.validation = newValidationState; broadcast( new PartValidationEvent( this ) ); } } public final boolean visible() { if( this.visibilityFunctionResult == null ) { if( this.visibilityFunctionInitializing ) { this.visibilityFunctionResult = Literal.FALSE.evaluate( new FunctionContext() ); } else { this.visibilityFunctionInitializing = true; try { final FunctionResult fr = initExpression ( initVisibleWhenFunction(), Boolean.class, Literal.TRUE, new Runnable() { public void run() { broadcast( new PartVisibilityEvent( SapphirePart.this ) ); } } ); final boolean visibilityAccessedDuringInit = ( this.visibilityFunctionResult != null ); this.visibilityFunctionResult = fr; if( visibilityAccessedDuringInit && ( (Boolean) fr.value() ).booleanValue() == true ) { broadcast( new PartVisibilityEvent( this ) ); } } finally { this.visibilityFunctionInitializing = false; } } } return (Boolean) this.visibilityFunctionResult.value(); } public boolean setFocus() { return false; } public boolean setFocus( final ModelPath path ) { return false; } public final boolean setFocus( final String path ) { return setFocus( new ModelPath( path ) ); } public IContext getDocumentationContext() { return null; } public SwtResourceCache getSwtResourceCache() { if( this.imageCache == null ) { this.imageCache = ( this.parent == null ? new SwtResourceCache() : this.parent.getSwtResourceCache() ); } return this.imageCache; } public final boolean attach( final Listener listener ) { return this.listeners.attach( listener ); } public final boolean detach( final Listener listener ) { return this.listeners.detach( listener ); } protected final void broadcast( final Event event ) { this.listeners.broadcast( event ); } @Deprecated public final void addListener( final SapphirePartListener listener ) { if( this.listenersDeprecated == null ) { this.listenersDeprecated = Collections.singleton( listener ); } else { this.listenersDeprecated = new HashSet<SapphirePartListener>( this.listenersDeprecated ); this.listenersDeprecated.add( listener ); } } @Deprecated public final void removeListener( final SapphirePartListener listener ) { if( this.listenersDeprecated != null ) { if( this.listenersDeprecated.contains( listener ) ) { if( this.listenersDeprecated.size() == 1 ) { this.listenersDeprecated = null; } else { this.listenersDeprecated = new HashSet<SapphirePartListener>( this.listenersDeprecated ); this.listenersDeprecated.remove( listener ); } } } } @Deprecated public final Set<SapphirePartListener> getListeners() { if( this.listenersDeprecated == null) { return Collections.emptySet(); } else { return this.listenersDeprecated; } } public final PropertyDef resolve( final String propertyName ) { return resolve( this.modelElement, propertyName ); } public final PropertyDef resolve( final Element modelElement, String propertyName ) { return resolve( modelElement, propertyName, this.params ); } public static final PropertyDef resolve( final Element modelElement, String propertyName, final Map<String,String> params ) { if( propertyName != null ) { propertyName = substituteParams( propertyName.trim(), params ); final ElementType type = modelElement.type(); final PropertyDef property = type.property( propertyName ); if( property == null ) { throw new RuntimeException( "Could not find property " + propertyName + " in " + type.getQualifiedName() ); } return property; } return null; } public final String substituteParams( final String str ) { return substituteParams( str, this.params ); } public static final String substituteParams( final String str, final Map<String,String> params ) { String result = str; if( str != null && str.contains( "@{" ) ) { for( final Map.Entry<String,String> param : params.entrySet() ) { final StringBuilder token = new StringBuilder(); token.append( "@{" ); token.append( param.getKey() ); token.append( '}' ); result = result.replace( token, param.getValue() ); } } return result; } /** * Returns the action contexts defined by this part. The default implementation returns an empty set. * Part implementations should override to define action contexts. * * @return the action contexts defined by this part */ public Set<String> getActionContexts() { return Collections.emptySet(); } public String getMainActionContext() { final Set<String> contexts = getActionContexts(); if( ! contexts.isEmpty() ) { return contexts.iterator().next(); } return null; } public final SapphireActionGroup getActions() { final String context = getMainActionContext(); if( context != null ) { return getActions( context ); } return null; } public final SapphireActionGroup getActions( final String context ) { if( this.actions == null ) { this.actions = new HashMap<String,SapphireActionGroup>(); for( String ctxt : getActionContexts() ) { final SapphireActionGroup actionsForContext = new SapphireActionGroup( this, ctxt ); this.actions.put( ctxt.toLowerCase(), actionsForContext ); } } return this.actions.get( context.toLowerCase() ); } public final SapphireAction getAction( final String id ) { for( final String context : getActionContexts() ) { final SapphireAction action = getActions( context ).getAction( id ); if( action != null ) { return action; } } if( this.parent != null ) { return this.parent.getAction( id ); } return null; } public <A> A adapt( final Class<A> adapterType ) { A result = service( MasterConversionService.class ).convert( this, adapterType ); if( result == null ) { final Element element = getLocalModelElement(); if( element != null ) { result = element.adapt( adapterType ); } } if( result == null && this.parent != null ) { result = this.parent.adapt( adapterType ); } return result; } /** * Returns the service of the specified type from the part service context. * * <p>Service Context: <b>Sapphire.Part</b></p> * * @param <S> the type of the service * @param type the type of the service * @return the service or <code>null</code> if not available */ public final <S extends Service> S service( final Class<S> type ) { final List<S> services = services( type ); return ( services.isEmpty() ? null : services.get( 0 ) ); } /** * Returns services of the specified type from the part service context. * * <p>Service Context: <b>Sapphire.Part</b></p> * * @param <S> the type of the service * @param type the type of the service * @return the list of services or an empty list if none are available */ public final <S extends Service> List<S> services( final Class<S> type ) { if( this.serviceContext == null ) { this.serviceContext = new PartServiceContext( this ); } return this.serviceContext.services( type ); } /** * Executes a job after this part has been fully initialized. If the part has already been * initialized, the job is executed immediately. * * @param job the job to perform * @return true if the job has been performed prior to returning to the caller, false otherwise * @throws IllegalArgumentException if job is null */ public final boolean executeAfterInitialization( final Runnable job ) { if( job == null ) { throw new IllegalArgumentException(); } if( initialized() ) { job.run(); return true; } else { attach ( new FilteredListener<PartInitializationEvent>() { @Override protected void handleTypedEvent( final PartInitializationEvent event ) { detach( this ); job.run(); } } ); return false; } } public void dispose() { boolean performOnDisposeTasks = false; synchronized( this ) { if( ! this.disposed ) { this.disposed = true; performOnDisposeTasks = true; } } if( performOnDisposeTasks ) { if( this.parent == null && this.imageCache != null ) { this.imageCache.dispose(); } if( this.actions != null ) { for( SapphireActionGroup actionsForContext : this.actions.values() ) { actionsForContext.dispose(); } } if( this.serviceContext != null ) { this.serviceContext.dispose(); } if( this.visibilityFunctionResult != null ) { this.visibilityFunctionResult.dispose(); } broadcast( new DisposeEvent() ); } } public final boolean disposed() { synchronized( this ) { return this.disposed; } } @Override public final void close() { dispose(); } protected final class ImageManager { private final Function imageFunction; private final Function defaultValueFunction; private boolean initialized; private boolean broadcastImageEvents; private FunctionResult imageFunctionResult; private ImageData baseImageData; private ImageDescriptor base; private ImageDescriptor error; private ImageDescriptor warning; private ImageDescriptor current; public ImageManager( final Function imageFunction ) { this( imageFunction, Literal.NULL ); } public ImageManager( final Function imageFunction, final Function defaultValueFunction ) { this.imageFunction = imageFunction; this.defaultValueFunction = defaultValueFunction; } private void init() { if( ! this.initialized ) { this.initialized = true; this.imageFunctionResult = initExpression ( this.imageFunction, ImageData.class, this.defaultValueFunction, new Runnable() { public void run() { refresh(); } } ); attach ( new FilteredListener<PartValidationEvent>() { @Override protected void handleTypedEvent( PartValidationEvent event ) { refresh(); } } ); refresh(); this.broadcastImageEvents = true; } } public ImageDescriptor getImage() { init(); this.broadcastImageEvents = true; return this.current; } private void refresh() { final ImageDescriptor old = this.current; if( this.imageFunctionResult != null ) { final ImageData newBaseImageData = (ImageData) this.imageFunctionResult.value(); if( this.baseImageData != newBaseImageData ) { this.baseImageData = newBaseImageData; this.base = SwtUtil.toImageDescriptor( this.baseImageData ); this.error = null; this.warning = null; } if( this.base == null ) { this.current = null; } else { this.current = this.base; final Status st = validation(); final Status.Severity severity = st.severity(); if( severity == Status.Severity.ERROR ) { if( this.error == null ) { this.error = new ProblemOverlayImageDescriptor( this.base, Status.Severity.ERROR ); } this.current = this.error; } else if( severity == Status.Severity.WARNING ) { if( this.warning == null ) { this.warning = new ProblemOverlayImageDescriptor( this.base, Status.Severity.WARNING ); } this.current = this.warning; } } } if( this.broadcastImageEvents && this.current != old ) { broadcast( new ImageChangedEvent( SapphirePart.this ) ); } } public void dispose() { if( this.imageFunctionResult != null ) { this.imageFunctionResult.dispose(); } } } public static abstract class PartEvent extends Event { private final SapphirePart part; public PartEvent( final SapphirePart part ) { this.part = part; } public SapphirePart part() { return this.part; } @Override protected Map<String,String> fillTracingInfo( Map<String,String> info ) { super.fillTracingInfo( info ); final Element element = this.part.getLocalModelElement(); info.put( "part", this.part.getClass().getName() + '(' + System.identityHashCode( this.part ) + ')' ); info.put( "element", element.type().getQualifiedName() + '(' + System.identityHashCode( element ) + ')' ); return info; } } public static final class PartInitializationEvent extends PartEvent { public PartInitializationEvent( final SapphirePart part ) { super( part ); } } public static final class LabelChangedEvent extends PartEvent { public LabelChangedEvent( final SapphirePart part ) { super( part ); } } public static final class DescriptionChangedEvent extends PartEvent { public DescriptionChangedEvent( final SapphirePart part ) { super( part ); } } public static final class ImageChangedEvent extends PartEvent { public ImageChangedEvent( final SapphirePart part ) { super( part ); } } public static final class FocusReceivedEvent extends PartEvent { public FocusReceivedEvent( final SapphirePart part ) { super( part ); } } public static final SapphirePart create( final ISapphirePart parent, final Element element, final PartDef definition, final Map<String,String> params ) { final SapphirePart part = createWithoutInit( parent, element, definition, params ); part.initialize(); return part; } public static final SapphirePart createWithoutInit( final ISapphirePart parent, final Element element, final PartDef definition, final Map<String,String> params ) { if( element == null ) { throw new IllegalArgumentException(); } SapphirePart part = null; Map<String,String> partParams = params; PartDef def = definition; if( definition instanceof PropertyEditorDef ) { part = new PropertyEditorPart(); } else if( definition instanceof TextDef ) { part = new TextPart(); } else if( definition instanceof LineSeparatorDef ) { part = new LineSeparatorPart(); } else if( definition instanceof SpacerDef ) { part = new SpacerPart(); } else if( definition instanceof ActuatorDef ) { part = new ActuatorPart(); } else if( definition instanceof CustomFormComponentDef ) { final JavaType customPartImplClass = ( (CustomFormComponentDef) definition ).getImplClass().target(); if( customPartImplClass != null ) { try { part = (SapphirePart) ( (Class<?>) customPartImplClass.artifact() ).newInstance(); } catch( Exception e ) { Sapphire.service( LoggingService.class ).log( e ); } } } else if( definition instanceof StaticTextFieldDef ) { part = new StaticTextFieldPart(); } else if( definition instanceof GroupDef ) { part = new GroupPart(); } else if( definition instanceof WithDef ) { final String path = ( (SapphirePart) parent ).substituteParams( ( (WithDef) definition ).getPath().text() ); if( path.endsWith( ".." ) ) { part = new WithImpliedPart(); } else { final Property property = element.property( path ); if( property.definition() instanceof ImpliedElementProperty ) { part = new WithImpliedPart(); } else { part = new WithPart(); } } } else if( definition instanceof DetailSectionDef ) { part = new DetailSectionPart(); } else if( definition instanceof DialogDef ) { part = new DialogPart(); } else if( definition instanceof WizardPageDef ) { part = new WizardPagePart(); } else if( definition instanceof SectionDef ) { part = new SectionPart(); } else if( definition instanceof SectionRef ) { final SectionRef ref = (SectionRef) definition; def = ref.getSection().target(); if( def == null ) { final String msg = couldNotResolveSection.format( ref.getSection().text() ); throw new IllegalArgumentException( msg ); } else { partParams = new HashMap<String,String>( params ); for( ISapphireParam param : ref.getParams() ) { final String paramName = param.getName().text(); final String paramValue = param.getValue().text(); if( paramName != null && paramValue != null ) { partParams.put( paramName, paramValue ); } } return createWithoutInit( parent, element, def, partParams ); } } else if( definition instanceof FormComponentRef ) { final FormComponentRef inc = (FormComponentRef) definition; def = inc.getPart().target(); if( def == null ) { final String msg = couldNotResolveInclude.format( inc.getPart().text() ); throw new IllegalArgumentException( msg ); } else { partParams = new HashMap<String,String>( params ); for( ISapphireParam param : inc.getParams() ) { final String paramName = param.getName().text(); final String paramValue = param.getValue().text(); if( paramName != null && paramValue != null ) { partParams.put( paramName, paramValue ); } } return createWithoutInit( parent, element, def, partParams ); } } else if( definition instanceof TabGroupDef ) { part = new TabGroupPart(); } else if( definition instanceof HtmlPanelDef ) { part = new HtmlPanelPart(); } else if( definition instanceof SplitFormDef ) { part = new SplitFormPart(); } else if( definition instanceof SplitFormSectionDef ) { part = new SplitFormSectionPart(); } else if( definition instanceof CompositeDef ) { part = new CompositePart(); } else if( definition instanceof FormDef ) { part = new FormPart(); } else if( definition instanceof MasterDetailsEditorPageDef ) { part = new MasterDetailsEditorPagePart(); } else if( definition instanceof FormEditorPageDef ) { part = new FormEditorPagePart(); } if( part == null ) { throw new IllegalStateException(); } part.init( parent, element, def, partParams ); return part; } }