Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [e4-dev] New reply to Re: Setting Custom Context Variables In A Part's Context Before Part Creation by Rob Hatcherson

Title: Eclipse Community Forums

@Rob @Sopot

Thanks for sharing this. I put your code to good use today. (All I did was add an “eventBroker.unsubscribe(this)” after processing to get rid of the Handler ... necessary or voodoo?)

 

 

Von: webmaster@xxxxxxxxxxx [mailto:webmaster@xxxxxxxxxxx]
Gesendet: Freitag, 14. September 2012 18:44
An: Keimel, Christoph
Betreff: New reply to Re: Setting Custom Context Variables In A Part's Context Before Part Creation by Rob Hatcherson

 

Subject: Re: Setting Custom Context Variables In A Part's Context Before Part Creation

Author: Rob Hatcherson

Date: Fri, 14 September 2012 11:43

Thanks Sopot - that worked perfectly.

In summary, when a new part is created - e.g. through MBasicFactory.INSTANCE.createPart(), or partService.createPart(someDescriptorId), or probably any other way - the context won't be non-null until the part is shown though the rendering machinery as noted by Sopot above. By the time partService.showPart or partService.activate returns the part contribution's @PostConstruct method has already been called.

To set extra data in the context and make it available for injection prior to the part contribution's @PostConstruct method being called we can use Sopot's suggestion. The method below was swiped from a project we have in development, and demonstrates how we borrowed from the code in the link noted above. There are a few things in here that prevent it from being used as-is, but with just a bit of tailoring some of this might be useful to somebody.

Some of this content was borrowed from tutorials by Lars Vogel, Jonas Helming, and others.

The "View" class used in this snippet is a relatively simple convenience that sits above all our part contribution classes, and IContainedObject is the thing we wanted to stuff in the new part's context. One could easily modify this to take a more general set of data values to stuff.

 
public void showView(
    View requestingView,
    Class<? extends View> viewClass,
    String targetPartStackId,
    final IContainedObject containedObject
)
{
    IEclipseContext context = requestingView.getPart().getContext() ;
 
    MApplication app = context.get( MApplication.class ) ;
    final EModelService modelService = context.get( EModelService.class ) ;
    
    MUIElement uiElement = modelService.find( targetPartStackId, app ) ;
 
    if( uiElement != null &&
        uiElement instanceof MPartStack )
    {
        MPartStack partStack = (MPartStack)uiElement ;
 
        // Either of these works.  Not sure which is best practice.
        // It probably is a tradeoff between programmatic convenience
        // and having to add stuff to some Application or fragment
        // e4xmi file.  Note that is part descriptors are used then
        // some of the calls made below are not necessary because the
        // property values are loaded from the e4xmi file.
 
        final MPart part = MBasicFactory.INSTANCE.createPart() ;
        //final MPart part = partService.createPart( "com.zedasoft.viewer4.fc.view.e4.testpartdescriptor" ) ;
 
        part.setLabel( containedObject.getDisplayName().toString() ) ;                
        part.setCloseable( true ) ;
        part.setToBeRendered( true ) ;
        part.setVisible( true ) ;
 
        //part.setElementId( viewClass.getName() + ":" + _secondaryId++ ) ;
        part.setContributionURI( viewClass.getName() ) ;
 
        // Set up a handler to set some data in the part's context so
        // it can be available to inject into the part's contribution
        // and be there when the @PostConstruct method is called.  Most
        // of the code in this block was borrowed from:
        //
        // https://bugs.eclipse.org/bugs/attachment.cgi?id=219843
 
        {
            IEventBroker eventBroker = context.get( IEventBroker.class ) ;
    
            eventBroker.subscribe( UIEvents.Context.TOPIC_CONTEXT, new EventHandler() {
                public void handleEvent( Event event )
                {
                    Object origin = event.getProperty( UIEvents.EventTags.ELEMENT ) ;
                    Object context = event.getProperty( UIEvents.EventTags.NEW_VALUE ) ;
                    
                    if( ( origin instanceof MHandlerContainer ) &&
                        ( UIEvents.EventTypes.SET.equals( event.getProperty( UIEvents.EventTags.TYPE ) ) &&
                        context instanceof IEclipseContext ) )
                    {
                        IEclipseContext eclipseContext = (IEclipseContext)context ;
                        MPart contextPart = eclipseContext.get( MPart.class ) ;
                        
                        if( contextPart == part )
                        {
                            // Set extra context data here.
                            
                            eclipseContext.set( View.CONTEXT_CONTAINED_OBJECT, containedObject ) ;
                        }
                    }
                }
            } ) ;
        }
        
        partStack.getChildren().add( part ) ;
 
        {
            EPartService partService = context.get( EPartService.class ) ;
 
            // Either of these works.  The latter one probably is best practice.
            //partService.showPart( part, EPartService.PartState.ACTIVATE ) ;                
            partService.activate( part ) ;
        }
    }
    else
    {
        Logger logger = context.get( Logger.class ) ;
        logger.error( "Couldn't find a part stack with id \"" + targetPartStackId + "\"." ) ;
    }
}


All that aside, this general topic probably is worth further discussion. It seems like it would be common in drill-down presentations to want a value present in a new part's context before the contribution springs to life. If true, then one needs to wonder why it isn't possible to simply do this before the part is shown:

newPart.getContext().set(...whatever...)

This obviously is far simpler than the event handler workaround. I can imagine reasons why context creation is deferred, but it definitely led to some hoop-jumping in this situation. Knowing little about the rationale behind E4 internals this may be a naive suggestion, but the getContext() method feels like a candidate for an "if you have it then return it, else create it then return it" approach. Then the user can put whatever they want in there, and the framework can take care of the remainder of the setup when the part is finally added to UI object graph and the rest of the context ancestry can be determined.

[ Reply ][ Quote ][ View Topic/Message ][ Unsubscribe from this topic ]

 


Back to the top