Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Setting Custom Context Variables In A Part's Context Before Part Creation
Setting Custom Context Variables In A Part's Context Before Part Creation [message #912414] Thu, 13 September 2012 14:35 Go to next message
Rob Hatcherson is currently offline Rob HatchersonFriend
Messages: 27
Registered: July 2009
Location: Fort Worth, TX, USA
Junior Member
I have a situation where I'd like to establish a detail object of interest for some part before the part and its view/contribution are created. The part's associated context seemed like a logical place to do this since the object of interest could be injected into the detail view contribution and be available to its @PostConstruct method.

However... it appears that the part's context is not created until the part is already in the renderer, so I don't get an opportunity to set the object of interest in the part's associated context until after the @PostConstruct method is called. This has led to some slightly clumsy code in the view contributions for the parts. Things I could have gotten over with in the @PostConstruct method now have to be delayed until some later @Inject setter is called (that approach works fine BTW, but it feels kind of out-of-the-loop).

I tried creating a child context of the perspective's context and setting it on the new part prior to creation/activation; when I did this the framework created the part and associated view contribution but the contribution's @PostConstruct method was never called. Maybe this would work and I'm just missing some additional set-up calls (?).

In my case at least it would be smoother if there were a way to get custom context variables established - in the part's associated context and not upstream of it - before the part is created/activated through the part service.

Is there a way to do this?
Re: Setting Custom Context Variables In A Part's Context Before Part Creation [message #912427 is a reply to message #912414] Thu, 13 September 2012 15:03 Go to previous messageGo to next message
Sopot Cela is currently offline Sopot CelaFriend
Messages: 597
Registered: December 2010
Senior Member

The context is created before the part is sent to the presentation engine (before createWidget in PartRenderingEngine class is called) but there is no specific hook you can grab to. A really quick thought is to use the IEventBroker. You can subscribe to all kinds of events there and specifically you can listen for coming and going of contexts. So you subscribe to the context's creations, check if it's your part's contexts and do your specific stuff with it. That would easily give you access to your context before the rendering. I have to run so I can't elaborate how to subscribe to the contexts coming and going but I've done it here: https://bugs.eclipse.org/bugs/attachment.cgi?id=219843 Check out the registerModelListeners. It can be done more easily through DI also.
Re: Setting Custom Context Variables In A Part's Context Before Part Creation [message #913040 is a reply to message #912427] Fri, 14 September 2012 16:43 Go to previous messageGo to next message
Rob Hatcherson is currently offline Rob HatchersonFriend
Messages: 27
Registered: July 2009
Location: Fort Worth, TX, USA
Junior Member
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.
Re: Setting Custom Context Variables In A Part's Context Before Part Creation [message #1391061 is a reply to message #913040] Mon, 30 June 2014 11:43 Go to previous messageGo to next message
Velganesh Subramanian is currently offline Velganesh SubramanianFriend
Messages: 67
Registered: July 2009
Member
Is there any new approach for such situations? I have a similar problem.
Re: Setting Custom Context Variables In A Part's Context Before Part Creation [message #1396700 is a reply to message #1391061] Tue, 08 July 2014 17:05 Go to previous message
Brian de Alwis is currently offline Brian de AlwisFriend
Messages: 194
Registered: January 2012
Senior Member

An alternative is to create your own MPart subclasses and place your data directly on the instance.

Brian.


Eclipse Platform committer. Ask me about Eclipse support, training, and consulting.
Previous Topic:Compatibility View not initialized
Next Topic:Addons execution order changed in Eclipse 4.4
Goto Forum:
  


Current Time: Fri Dec 19 20:31:12 GMT 2014

Powered by FUDForum. Page generated in 0.03141 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software