Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » Eclipse 4 » Presenting an MPart in a dialog
Presenting an MPart in a dialog [message #1726484] Mon, 14 March 2016 09:37 Go to next message
Peter Kullmann is currently offline Peter KullmannFriend
Messages: 240
Registered: July 2009
Senior Member
I would like to show an MPart inside a dialog and I'm facing some issues. What I did was the following:

public class PartDialog extends Dialog {

    @Inject
    private EPartService partService;

    @Inject
    private IPresentationEngine engine;

    @Inject
    private IEclipseContext parentContext;

    public PartDialog(Shell parentShell) {
        super(parentShell);
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        Composite composite = (Composite) super.createDialogArea(parent);

        Composite partHolder = new Composite(composite, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(partHolder);
        partHolder.setLayout(new FillLayout());

        IEclipseContext dialogContext = parentContext
                .createChild("dialog context");
        dialogContext.set(Shell.class, getShell());

        MPart part = partService.createPart("my.partdescriptor.id");
        engine.createGui(part, composite, dialogContext);

        return composite;
    }

}


This renders the part nicely inside the dialog. The problem is with a popup menu of the part. It shows but does not execute any handlers. In fact, no handlers are added to the context of the part.

It seems that the part must participate somewhere in the model (which it doesn't yet). It is not clear where in the model I should add the part.

Any hints and pointers are greatly appreciated,
Peter
Re: Presenting an MPart in a dialog [message #1727161 is a reply to message #1726484] Sun, 20 March 2016 14:48 Go to previous messageGo to next message
Peter Kullmann is currently offline Peter KullmannFriend
Messages: 240
Registered: July 2009
Senior Member
I found a way to do this. It's not so elegant but at least it works and I can re-use most of my dialogs in e4 with little changes. The idea is to use a MDialog model element to represent the dialog and use a special renderer for this. The renderer doesn't do a lot because the dialog was created before the renderer is called. The main pieces are the following:

First, the jface dialog:

    @Override
    protected Control createDialogArea(Composite parent) {
        Composite comp = (Composite) super.createDialogArea(parent);

        Composite partHolder = new Composite(comp, SWT.NONE);
        GridDataFactory.fillDefaults().grab(true, true).applyTo(partHolder);
        partHolder.setLayout(new FillLayout());

        EModelService modelService = parentContext.get(EModelService.class);
        MDialog dialog = modelService.createModelElement(MDialog.class);
        dialog.getPersistedState().put(IPresentationEngine.CUSTOM_RENDERER_KEY,
                "bundleclass://testdialog/testdialog.DialogRenderer");
        dialog.getTransientData().put("jface-dialog", this);
        dialog.getTransientData().put("part-holder", partHolder);
        MWindow window = parentContext.get(MWindow.class);
        window.getWindows().add(dialog);

        EPartService partService = parentContext.get(EPartService.class);
        MPart part = partService.createPart("my.partdescriptor.id");
        dialog.getChildren().add(part);

        return comp;
    }


So, during creation of the dialog controls the MDialog element is added to the application model and connected to the dialog (using transient data). And: A custom renderer is required for the MDialog element. Here comes the renderer:

public class DialogRenderer extends SWTPartRenderer {

    @Override
    public Object createWidget(MUIElement element, Object parent) {
        if (!(element instanceof MDialog)) {
            return null;
        }
        Dialog dialog = element.getTransientData().get("jface-dialog");
        bindWidget(element, dialog.getShell());

        IEclipseContext localContext = getContext(element);
        localContext.set(Shell.class, dialog.getShell());
        localContext.set(E4Workbench.LOCAL_ACTIVE_SHELL, dialog.getShell());

        dialog.getShell().addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent e) {
                element.setRenderer(false);
                MWindow container = (MWindow) ((EObject) element).eContainer();
                if (container != null) {
                    container.getWindows().remove(element);
                }
            }
        });

        return dialog.getShell();
    }

    @Override
    public Object getUIContainer(MUIElement element) {
        MUIElement parent = element.getParent();
        if (parent == null) {
            // might be a detached window
            parent = (MUIElement) ((EObject) element).eContainer();
            return parent == null ? null : parent.getWidget();
        }

        if (!(parent instanceof MDialog))
            throw new RuntimeException(
                    "Expected a MDialog as parent in " + element
                            + "\nActually got: " + parent);
        return ((MDialog)parent).getTransientData().get("part-holder");
    }

    @Override
    @PostConstruct
    public void init(IEclipseContext context) {
        super.init(context);
    }
}


The renderer returns the dialog shell as widget for the dialog and removes the MDialog element from the model as soon as the shell is disposed. The dialog's children (ie the part I would like to show inside the dialog) will be rendered inside the partHolder composite. This is the purpose of the getUIContainer method.

With this, everything inside the dialog works as if it was another workbench window: Popup menus, key bindings etc.

Peter
Re: Presenting an MPart in a dialog [message #1727170 is a reply to message #1727161] Sun, 20 March 2016 18:31 Go to previous messageGo to next message
Thomas Schindl is currently offline Thomas SchindlFriend
Messages: 6633
Registered: July 2009
Senior Member
I would discourage anyone to use the MDialog stuff! It is provisional
and IMHO completely broken in its current design!

Tom

On 20.03.16 15:48, Peter Kullmann wrote:
> I found a way to do this. It's not so elegant but at least it works and
> I can re-use most of my dialogs in e4 with little changes. The idea is
> to use a MDialog model element to represent the dialog and use a special
> renderer for this. The renderer doesn't do a lot because the dialog was
> created before the renderer is called. The main pieces are the following:
>
> First, the jface dialog:
>
>
> @Override
> protected Control createDialogArea(Composite parent) {
> Composite comp = (Composite) super.createDialogArea(parent);
>
> Composite partHolder = new Composite(comp, SWT.NONE);
> GridDataFactory.fillDefaults().grab(true, true).applyTo(partHolder);
> partHolder.setLayout(new FillLayout());
>
> EModelService modelService = parentContext.get(EModelService.class);
> MDialog dialog = modelService.createModelElement(MDialog.class);
>
> dialog.getPersistedState().put(IPresentationEngine.CUSTOM_RENDERER_KEY,
> "bundleclass://testdialog/testdialog.DialogRenderer");
> dialog.getTransientData().put("jface-dialog", this);
> dialog.getTransientData().put("part-holder", partHolder);
> MWindow window = parentContext.get(MWindow.class);
> window.getWindows().add(dialog);
>
> EPartService partService = parentContext.get(EPartService.class);
> MPart part = partService.createPart("my.partdescriptor.id");
> dialog.getChildren().add(part);
>
> return comp;
> }
>
>
> So, during creation of the dialog controls the MDialog element is added
> to the application model and connected to the dialog (using transient
> data). And: A custom renderer is required for the MDialog element. Here
> comes the renderer:
>
>
> public class DialogRenderer extends SWTPartRenderer {
>
> @Override
> public Object createWidget(MUIElement element, Object parent) {
> if (!(element instanceof MDialog)) {
> return null;
> }
> Dialog dialog = element.getTransientData().get("jface-dialog");
> bindWidget(element, dialog.getShell());
>
> IEclipseContext localContext = getContext(element);
> localContext.set(Shell.class, dialog.getShell());
> localContext.set(E4Workbench.LOCAL_ACTIVE_SHELL, dialog.getShell());
>
> dialog.getShell().addDisposeListener(new DisposeListener() {
> @Override
> public void widgetDisposed(DisposeEvent e) {
> element.setRenderer(false);
> MWindow container = (MWindow) ((EObject)
> element).eContainer();
> if (container != null) {
> container.getWindows().remove(element);
> }
> }
> });
>
> return dialog.getShell();
> }
>
> @Override
> public Object getUIContainer(MUIElement element) {
> MUIElement parent = element.getParent();
> if (parent == null) {
> // might be a detached window
> parent = (MUIElement) ((EObject) element).eContainer();
> return parent == null ? null : parent.getWidget();
> }
>
> if (!(parent instanceof MDialog))
> throw new RuntimeException(
> "Expected a MDialog as parent in " + element
> + "\nActually got: " + parent);
> return ((MDialog)parent).getTransientData().get("part-holder");
> }
>
> @Override
> @PostConstruct
> public void init(IEclipseContext context) {
> super.init(context);
> }
> }
>
>
> The renderer returns the dialog shell as widget for the dialog and
> removes the MDialog element from the model as soon as the shell is
> disposed. The dialog's children (ie the part I would like to show inside
> the dialog) will be rendered inside the partHolder composite. This is
> the purpose of the getUIContainer method.
>
> With this, everything inside the dialog works as if it was another
> workbench window: Popup menus, key bindings etc.
>
> Peter
>
Re: Presenting an MPart in a dialog [message #1727192 is a reply to message #1727170] Mon, 21 March 2016 08:13 Go to previous messageGo to next message
Peter Kullmann is currently offline Peter KullmannFriend
Messages: 240
Registered: July 2009
Senior Member
I agree. But for me this was an easy way to connect my existing JFace dialogs with the model (in order to get all the key bindings and context menus to work). I could have taken a normal MWindow instead of MDialog. But MDialog is just a bit more expressive when looking at the runtime model.

Peter


Thomas Schindl wrote on Sun, 20 March 2016 19:31
I would discourage anyone to use the MDialog stuff! It is provisional
and IMHO completely broken in its current design!

Tom

Re: Presenting an MPart in a dialog [message #1727193 is a reply to message #1727192] Mon, 21 March 2016 08:31 Go to previous message
Dirk Fauth is currently offline Dirk FauthFriend
Messages: 2850
Registered: July 2012
Senior Member
The only problem could face in the future is that MDialog is removed completely which will then break your code on updating.
Previous Topic:JavaFX Interoperability with e4/swt/osgi
Next Topic:Projects dissappears on Mars
Goto Forum:
  


Current Time: Sat Jun 25 15:21:18 GMT 2022

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

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

Back to the top