@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: [email protected] [mailto:[email protected]]
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<index.php?t=post&reply_to=913040> ][ 
Quote<index.php?t=post&reply_to=913040&quote=true> ][ View 
Topic/Message<index.php?t=rview&goto=913040#msg_913040> ][ Unsubscribe from 
this topic<index.php?t=rview&th=375910> ]



_______________________________________________
e4-dev mailing list
[email protected]
https://dev.eclipse.org/mailman/listinfo/e4-dev

Reply via email to