Presenting an MPart in a dialog [message #1726484] |
Mon, 14 March 2016 05:37  |
Eclipse User |
|
|
|
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 10:48   |
Eclipse User |
|
|
|
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 14:31   |
Eclipse User |
|
|
|
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
>
|
|
|
|
|
Powered by
FUDForum. Page generated in 0.03907 seconds