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

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));
}
}
...
}

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);
}
}

how to use text editors in Eclipse Mars programmatically, using the compatiblity layer?

I am using the 3.x-4.x compatibility layer and I'm attempting to open and use editors. Our existing code looks like this in the class that implements IPartListener2:
public void partOpened(IWorkbenchPartReference partRef) {
if (partRef instanceof IEditorReference) {
//force editor area visible
partRef.getPage().setEditorAreaVisible(true);
// if the editors are currently minimimized and we try to maximize them, then we'll cause a bug.
if (partRef.getPage().getPartState(partRef) == IWorkbenchPage.STATE_MINIMIZED) {
return; // so exit here
}
//check preferences
final boolean maximized = EnterpriseManager.isMaximized();
if (maximized) {
partRef.getPage().setPartState(partRef, 1);
}
}
}
The problem is now whenever an editor is opened in Mars, it doesn't open maximized as a tab on the page layout as before, but in a much smaller window size.
Also, selecting the Restore Icon on an open editor's rule bar causes erratic positioning of the editor with one section of the editor in one part of the layout and other sections displaying in other areas of the page layout.
How am I to implement correct, predictable usage of editors with the compatibility layer?
Just guessing but it may be that Eclipse 4 does not like the setEditorAreaActive and setPartState methods being called while partOpened is being processed. You could try using Display.asyncExec to delay calling these until after the partOpened code has completed.
Something like:
public void partOpened(final IWorkbenchPartReference partRef) {
Display.getDefault().asyncExec(new Runnable()
{
#Override
public void run()
{
if (partRef instanceof IEditorReference) {
//force editor area visible
partRef.getPage().setEditorAreaVisible(true);
// if the editors are currently minimimized and we try to maximize them, then we'll cause a bug.
if (partRef.getPage().getPartState(partRef) == IWorkbenchPage.STATE_MINIMIZED) {
return; // so exit here
}
//check preferences
final boolean maximized = EnterpriseManager.isMaximized();
if (maximized) {
partRef.getPage().setPartState(partRef, IWorkbenchPage.STATE_MAXIMIZED);
}
}
}
});
}

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

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");

Eclipse RCP4 close Part on exit / disable persistence of a Part?

i'm working on an Eclipse RCP4 project. I have different perspectives showing a set of Parts to choose informations from. After selecting what i want to see, a new Part opens and displays the objet i want to edit / view attibutes of.
I can open many parts of the same type. If i close the application, the eclipse framwork persists the position of all opened Parts. If i restart the application all previously opened Parts are open but without informations.
-How to prevent Eclipseframwork from persisting the state of Parts?
-How to close Parts on exit?
I'm searching for a way to add an "removeOnExit" tag to a Part and than close such a marked Part on exit.
Thanks in advance :)
With this you can close MParts with a specific Tag.
It seems you have to switch to the Perspective the Part is on, else it's not removed from the context wich will cause nullpointer exceptions.
#Inject
#Optional
public void doEvent(#EventTopic(EventConstants.EventTopics.CLOSE_PARTS_WITH_TAGS) String tagToClose, MApplication app,
EModelService eModelService, EPartService ePartService) {
MUIElement activePart = ePartService.getActivePart();
EPartService activePeServcie = null;
MPerspective activePerspective = null;
if (activePart instanceof MPart) {
activePeServcie = ((MPart) activePart).getContext().get(EPartService.class);
activePerspective = eModelService.getPerspectiveFor(activePart);
}
List<String> tags = new ArrayList<String>();
tags.add(tagToClose);
List<MPart> elementsWithTags = eModelService.findElements(app, null, MPart.class, tags);
for (MPart part : elementsWithTags) {
try {
logger.info("Closing part " + part.toString());
EPartService peService = part.getContext().get(EPartService.class);
peService.switchPerspective(eModelService.getPerspectiveFor(part));
peService.hidePart(part);
} catch (Exception e) {
logger.error(e);
}
}
if (activePart instanceof MPart && activePeServcie != null && activePerspective != null) {
activePeServcie.switchPerspective(activePerspective);
}
}
We too tried to migrate from Eclipse 3 to Eclipse 4.We used the comp layer and had a lot of problems with the migration. I had a similar problem with persistent store of the eclipse workbench. So parts and views had the same position as before restart.
The persistence paradigma in Eclipse 4 has changed. Please take a look here:
As far as I remember the call of configurer.setSaveAndRestore(false) does not work in Eclipse 4 correctly.

Remove "File, edit,...etc" menus from Eclipse RCP application

I want to remove the File, edit, Source, Refactor, etc. menus from my RCP application
Can I use hideActionSet() ? or what should I do ?
That's right; in your ApplicationWorkbenchWindowAdvisor, override postWindowOpen().
The tricky bit is usually figuring out the names of the actionsets that you want to remove, but you can use the old standby ALT-SHIFT-F2 (the default keybinding for 'Plugin-in Menu Spy') and click on one of the menu items that you want to remove.
Note that if the menu item is disabled, the spy won't give you any info on it.
public void postWindowOpen() {
runApplicationWorkbenchDelegate();
// remove unwanted UI contributions that eclipse makes by default
IWorkbenchWindow[] windows = PlatformUI.getWorkbench().getWorkbenchWindows();
for (int i = 0; i < windows.length; ++i) {
IWorkbenchPage page = windows[i].getActivePage();
if (page != null) {
// hide generic 'File' commands
page.hideActionSet("org.eclipse.ui.actionSet.openFiles");
// hide 'Convert Line Delimiters To...'
page.hideActionSet("org.eclipse.ui.edit.text.actionSet.convertLineDelimitersTo");
// hide 'Search' commands
page.hideActionSet("org.eclipse.search.searchActionSet");
// hide 'Annotation' commands
page.hideActionSet("org.eclipse.ui.edit.text.actionSet.annotationNavigation");
// hide 'Forward/Back' type navigation commands
page.hideActionSet("org.eclipse.ui.edit.text.actionSet.navigation");
}
}
}
Although the question is old:
Lars Vogel's tutorial about Eclipse Activities shows how to hide entire menus in an RCP application rather than removing single menu-entries.
EDIT:
Alternatively you can use the MenuManager attached to the workbench window to show or hide Menus/Contributions.
Try the following code to hide all menus:
WorkbenchWindow workbenchWin = (WorkbenchWindow)PlatformUI.getWorkbench().getActiveWorkbenchWindow();
MenuManager menuManager = workbenchWin.getMenuManager();
IContributionItem[] items = menuManager.getItems();
for(IContributionItem item : items) {
item.setVisible(false);
}