How to pass an object from one part to another part in Eclispe e4 RCP? - eclipse

I am building an application with eclipse e4 RCP. I have a navigator (similar to Navigator in eclipse IDE) and I would like to link it to an editor (similar to how a file in Navigator in eclipse IDE is linked to an editor). Currently I am using EPartService to open up my editor Part (by creating a new instance) when the user double clicks on a file in the Navigator tree. But I would like to pass it a parameter (a String or an Object) to let it know which file to open in the editor. I want to be able to open multiple editors for different nodes of the Navigator tree. I have done a lot of research on internet but could not find a solution. I think its a common problem and the e4 framework should provide an mechanism to pass such parameters from one Part to another Part. Current code is as below:
viewer.addDoubleClickListener(event -> {
final IStructuredSelection selection = (IStructuredSelection) event.getSelection();
FileNode file = null;
boolean partExists = false;
if (selection.getFirstElement() instanceof FileNode ) {
file = (FileNode ) selection.getFirstElement();
for (MPart part1 : partService.getParts()) {
if (part1.getLabel().equals(file.getName())) {
partService.showPart(part1, PartState.ACTIVATE);
partExists = true;
break;
}
}
if (!partExists) {
MPart part2 = partService
.createPart("com.parts.partdescriptor.fileeditor");
part2.setLabel(file.getName());
partService.showPart(part2, PartState.ACTIVATE);
}
}
});
Is it possible to say something like part2.setParameter("PARAM_NAME", "FILE_NAME"); ?

When you have an MPart you can call:
MPart mpart = ...
MyClass myClass = (MyClass)mpart.getObject();
to get your class for the part (the class defined in the 'Class URI' for the part in the Application.e4xmi). You can then call any methods you have defined on your part class.
You can also set data in the 'transient data' area of a part:
mpart.getTransientData().put("key", "data");
Object data = mpart.getTransientData().get("key");

Related

Open DialectEditor programmatically outside of main editor area (E3/E4 hybrid)

what I want to do:
In my RCP an E3/E4 hybrid I have a project and library based on sirius tree. The User can drag an drop item from the library tree to the project tree. This works fine and was no great problem to build in. So now I want to make the UI more usable. It should looks like this layout:
what works:
After application startup I open my library presentation with the DialectUIManager.
final DialectEditor editor = (DialectEditor)
DialectUIManager.INSTANCE.openEditor(siriusSession, description, monitor);
Okay, this works. But it open it in the editor in the part market as org.eclipse.ui.editorss. This it not what I want
what does not work:
I want to show it in the "Library Part". I can move it manually with the mouse after open the editor, but how can i tell DialectUIManager to open it direct there. Or how can I programmatically it move there.
I do a lot of google research but i don't found a solution. The only thing I found was a hint Pierre-Charles David https:// www. eclipse.org/forums/index.php?t=msg&th=998476&goto=1631138&#msg_1631138
If you need is simply to show the editor outside of the main editor
area, this is possible since Eclipse 4.2 (e4 does not really treat the
main editor area as something special), so you can have your editor
"around" another editor in the middle of other views.
But at this step I stuck. I also ask it in the Sirius Forum but they say its a Eclipse E4 problem
Thanks for help, code snippets or links to correct part of manual.
I've found a solution. It's not very nice, but it works. I execute these code here after the editors have opened.
What the code does:
He is looking for the MPlaceholder which has the ID: org. eclipse. ui. editorss. There he descends until he is with the parts. These are in the Compatibly editor mode. Then he chooses the part we wants to move out of and Attach them to the MPartStack target.
public static void movePart(MApplication application,
EModelService modelService) {
MPart partToMove = null;
MUIElement muiElement =
modelService.find("org.eclipse.ui.editorss", application);
if (muiElement instanceof MPlaceholder) {
MPlaceholder placeholder = (MPlaceholder) muiElement;
MUIElement ref = placeholder.getRef();
if (ref instanceof MArea) {
MArea area = (MArea) ref;
List<MPartSashContainerElement> children = area.getChildren();
for (MPartSashContainerElement mPartSashContainerElement
: children) {
if (mPartSashContainerElement instanceof MPartStack) {
MPartStack partStack = (MPartStack) mPartSashContainerElement;
List<MStackElement> children2 = partStack.getChildren();
for (MStackElement mStackElement : children2) {
if (mStackElement instanceof MPart) {
MPart part = (MPart) mStackElement;
// Library is the Editor Name wiche I want to move
if (part.getLabel().equals("Library")) {
partToMove = part;
break;
}
}
}
}
}
}
}
if (partToMove != null) {
moveElement(modelService, application, partToMove);
}
}
private static void moveElement(EModelService modelService,
MApplication application, MPart part) {
// target PartStack
MUIElement find = modelService.find("de.bsg.onesps.rcp.
partstack.library", application);
if (find instanceof MPartStack) {
MPartStack mPartStack = (MPartStack) find;
mPartStack.getChildren().add(part);
mPartStack.setSelectedElement(part);
}
}

Using e3x property view with e4 Selection service from EMF Model

I built a small e4 RCP application containing both an "e4 xmi" tree view populated by emf generated model code (using ComposedAdapterFactory) and an "e3 properties view".
Tried following "dirksmetric tutorial" to display property view in application.e4xmi (shared elements) with an empty property view.
To get a tree's selected element displayed in my property sheet (IItemPropertySource), I did the following things :
On my e4 treeviewer side, I use the e4 selection service in #createComposite:
// Register the viewer as a selection provider (to be consumed by the property view...)
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
#Override
public void selectionChanged(SelectionChangedEvent event) {
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
// set the selection to the service
selectionService.setSelection(
selection.size() == 1? selection.getFirstElement(): selection.toArray());
}
});
On the e3 "classical" property sheet side, I defined a couple of things :
I called IDE.registerAdapters in my ApplicationWorkbenchAdvisor#initialize.
I declared my property source adapter as follow in my plugin.xml :
extension point="org.eclipse.core.runtime.adapters">
factory adaptableType="org.eclipse.emf.ecore.EObject"
class="myappmodeler.properties.ModelPropertiesAdapter">
adapter type="org.eclipse.ui.views.properties.IPropertySource">
My ModelPropertiesAdapter#getAdapter returns a property source :
public Object getAdapter(Object adaptableObject, Class adapterType) {
if (adapterType== IPropertySource.class && adaptableObject instanceof EObject){
emfGlobalFactory = new ComposedAdapterFactory();
emfGlobalFactory.addAdapterFactory(new RepositorystructureItemProviderAdapterFactory());
emfGlobalFactory.addAdapterFactory(new ApplicationItemProviderAdapterFactory());
emfGlobalFactory.addAdapterFactory(new ServiceItemProviderAdapterFactory());
return new AdapterFactoryContentProvider(emfGlobalFactory).getPropertySource(adaptableObject);
}
return null;
}
My problem is this adapter is not even executed.
Currently using Eclipse neon (it was recently updated to synchronise E3 and E4 selection service)
https://bugs.eclipse.org/bugs/show_bug.cgi?id=403930
There are different ways to fix this problem, but for my case, these are the steps
I took to these steps to solve mine
Take control of the base model - create an interface which extends EObject
Create custom property provider, source and descriptor - extends org.eclipse.emf.edit.ui.provider.*
at runtime we need IItemPropertySource
Create a content provider class (extends AdapterFactoryContentProvider) and override createPropertySource with custom property source
Note; I also developed a table layout which means implementing custom ItemProvider (implement ITableItemLabelProvider) for individual elements in the model
Worked perfectly with ESelectionService
Hope these notes helps somebody

Eclipse RCP: Can I remove Orphaned Perspectives from the Perspective Bar?

I'm developing an RCP that has two product versions, a core app and one with some extensions. If a user opens the core app after having opened the extended app in the same workspace, eclipse detects a perspective used only in the extended app and makes a local copy of it, so it shows up in the perspective toolbar as an orphaned extension.
I created an activity to hide the extended app perspective when running the core app. That hides it from the perspective menu and the perspective shortcut menu, but it doesn't remove it from the perspective toolbar.I also tried detecting orphaned perspectives from the active page of the active workbench window (by looking for angle brackets in the label) and removing them with PlatformUI.getWorkbench().getPerspectiveRegistry().deletePerspective(perspective), but this doesn't affect the perspective toolbar either. The perspective I'm removing is not present in the core app.
Is there a way I can access the perspective toolbar programmatically so I can remove any orphaned perspectives? Or any other approach tha would work?
I thought a good solution would be creating a custom perspective switcher, but that path was blocked by an eclipse bug. There is a suggested workaround, but it did not work for me. I created a custom perspective switcher toolbar, but I could find no way to make it update when perspectives are opened or activated. My attempts are documented here.
I removed the orphan perspectives in a workspace shutdown hook, but for some reason an NPE is thrown by the E4 workbench (LazyStackRenderer line 238) when I select a perspective in the switcher that was opened but not selected when I launched the app.
I got it to work as desired by closing all open perspectives on shutdown, after storing their IDs in a preference value, and then opening them again when the app is launched in the WorkbenchWindowAdvisor. It's a bit of a hack, but it's the only way I could find to avoid the E4 workbench NPE, which also prevents setting the perspective from the toolbar until it's closed and re-opened from the Window menu.
Here's my code.
...
IWorkbench workbench = ...
static final String PERPSECTIVE_ID_1 = ...
static fnal String PERSPECTIVE_ID_2 = ...
static final String PREFERENCE_KEY = ...
workbench.addWorkbenchListener( new IWorkbenchListener() {
public boolean preShutdown( IWorkbench workbench, boolean forced ) {
IPerspectiveDescriptor[] openPerspectives = page.getOpenPerspectives();
page.closeAllPerspectives(false, false);
StringBuilder sb = new StringBuilder();
String delim = "";
for (IPerspectiveDescriptor persp : openPerspectives) {
if (!persp.getId().equals(PERSPECTIVE_ID_1) && !persp.getId().equals(PERSPECTIVE_ID_2) {
sb.append(delim + persp.getId());
delim = ";";
}
}
getPreferenceStore().setValue(PREF_KEY, sb.toString());
return true;
}
public void postShutdown( IWorkbench workbench ) {
}
});
class MyWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor {
static final String PRODUCT_ID_1 = ...
static final String PRODUCT_ID_2 = ...
static final String PREFERENCE_KEY = ...
...
#Override
public void postWindowOpen() {
IWorkbenchPage page = getWindowConfigurer().getWindow().getActivePage();
String savedOpenPerspectiveStr = getPreferenceStore().getString(PREFERENCE_KEY);
if (!"".equals(savedOpenPerspectiveStr)) {
List<IPerspectiveDescriptor> openPerspectives = new ArrayList<IPerspectiveDescriptor>();
String[] perspectiveIds = savedOpenPerspectiveStr.split(";");
if (perspectiveIds.length == 0) {
openPerspectives.add(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(savedOpenPerspectiveStr));
} else {
for (String id : perspectiveIds) {
openPerspectives.add(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(id));
}
}
//successively setting perspectives causes them to appear in the perspective switcher toolbar
for (IPerspectiveDescriptor persp : openPerspectives) {
page.setPerspective(persp);
}
}
//now we set the appropriate perspective
if (Platform.getProduct().getId().equals(PRODUCT_ID_1)) {
page.setPerspective(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(PERSPECTIVE_ID_1));
} else if (Platform.getProduct().getId().equals(PRODUCT_ID_2)) {
page.setPerspective(PlatformUI.getWorkbench().getPerspectiveRegistry().findPerspectiveWithId(PERSPECTIVE_ID_2));
}
}
...
}

How to retain the state of a treeviewer in Java RCP application?

I have a simple RCP application having couple of wizards out of which one is having a tree viewer. I want to retain the state of the selected item in the tree viewer next time I open that particular view. As of now I have implemented using static variables and its working fine.I want to know how it can be done in a better way?
//Sample Code
private static RepositoryLocationItem lastRepoItemSelected;
Composite parent=new Composite(SWT.NONE)
treeViewer = new TreeViewer(parent);
treeViewer.setContentProvider(new MovingBoxContentProvider());
treeViewer.setLabelProvider(new MovingBoxLabelProvider());
treeViewer.setInput(getInitalInput());
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
/* Setting the value of lastRepoItemSelected */
});
if(lastRepoItemSelected !=null)
{
treeViewer.setSelection(new StructuredSelection(lastRepoItemSelected),true);
}
Assuming this is a 3.x style RCP (your view extends ViewPart) you can use the saveState method to save your view state:
#Override
public void saveState(final IMemento memento)
{
// TODO set values in the 'memento'
}
You can then use the init method to restore values from the memento when the view is shown again:
#Override
public void init(final IViewSite site, final IMemento memento)
throws PartInitException
{
super.init(site, memento);
// TODO restore from 'memento'
}
Note: Mementos are persisted across restarts of your RCP so you need to store values in them which are valid in a new instance of the RCP.
Also look at the Eclipse wiki entry for more information.
For a WizardPage you can use the IDialogSettings. You must set this up in your Wizard using something like:
IDialogSettings pluginSettings = Activator.getDefault().getDialogSettings();
IDialogSettings wizardSettings = pluginSettings.getSection("id of your wizard");
if (wizardSettings == null) {
wizardSettings= new DialogSettings("id of your wizard");
pluginSettings.addSection(wizardSettings);
}
setDialogSettings(wizardSettings);
where Activator is your plugin activator class and "name of your wizard" is a id for your wizard (which can be anything as long as it is unique in your plugin).
In your wizard page you can then get the settings with:
IDialogSettings settings = getDialogSettings();
IDialogSettings has lots of methods for saving and restore various sorts of values, such as:
settings.put("key", "string value");
String value = settings.get("key");

Eclipse plugin : Get the enclosing class and member name

I have created a Eclipse plug in to printout the object in selection on press of a short cut key.
I have been able to do this ,but i also would like to add the current method and current class name in the log. I am not sure how to proceede further. I tried to search for breadcrumb API but i was not able to reference the package from my project. I am quite new to plugin developement could someone guide me as to how to achive my goal. Thanks in advance.
It really hard to get that stuff from Breadcrumb, you would have to use reflection to get it.
Here is the code to get current method from editor.
ITextEditor editor = (ITextEditor) PlatformUI.getWorkbench()
.getActiveWorkbenchWindow().getActivePage().getActiveEditor();
ITextSelection selection = (ITextSelection) editor
.getSelectionProvider().getSelection();
IEditorInput editorInput = editor.getEditorInput();
IJavaElement elem = JavaUI.getEditorInputJavaElement(editorInput);
if (elem instanceof ICompilationUnit) {
ICompilationUnit unit = (ICompilationUnit) elem;
IJavaElement selected = unit.getElementAt(selection.getOffset());
System.out.println("selected=" + selected);
System.out.println("selected.class=" + selected.getClass());
}