How do I reset perspective for Eclipse e4 RCP application? - eclipse-rcp

After building a perspective in application.e4xmi file, I am unable to reset perspective by calling IWorkbenchPage.resetPerspective().

I thought this may save others some time, as well as document it for myself.
The trick to being able to reset an e4 perspective is as follows (assumes a basic application.e4xmi with PerspectiveStack element):
In your application.e4xmi file, locate your PerspectiveStack under your Application/TrimmedWindow node. Record/set its ID.
In Eclipse 4 Model Editor, drag your Perspective(s) from underneath your PerspectiveStack to Application/Snippets. (This will cause your perspective IDs to register with IPerspectiveRegistry, and provide a pristine state).
Create new CopyPerspectiveSnippetProcessor. This will copy the perspectives in your snippets to your PerspectiveStack on startup. This makes it so you don't have to maintain two copies of each perspective element in your e4xmi file.
package com.example.application.processors;
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.MUIElement;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspective;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
/**
* Copies all snippet perspectives to perspective stack called "MainPerspectiveStack" In order to register/reset perspective and not have to sync two copies in
* e4xmi.
*
*/
public class CopyPerspectiveSnippetProcessor {
private static final String MAIN_PERSPECTIVE_STACK_ID = "MainPerspectiveStack";
#Execute
public void execute(EModelService modelService, MApplication application) {
MPerspectiveStack perspectiveStack = (MPerspectiveStack) modelService.find(MAIN_PERSPECTIVE_STACK_ID, application);
// Only do this when no other children, or the restored workspace state will be overwritten.
if (!perspectiveStack.getChildren().isEmpty())
return;
// clone each snippet that is a perspective and add the cloned perspective into the main PerspectiveStack
boolean isFirst = true;
for (MUIElement snippet : application.getSnippets()) {
if (snippet instanceof MPerspective) {
MPerspective perspectiveClone = (MPerspective) modelService.cloneSnippet(application, snippet.getElementId(), null);
perspectiveStack.getChildren().add(perspectiveClone);
if (isFirst) {
perspectiveStack.setSelectedElement(perspectiveClone);
isFirst = false;
}
}
}
}
}
Register your CopyPerspectiveSnippetProcess into your plugin.xml file.
<extension id="MainAppModel" point="org.eclipse.e4.workbench.model">
<processor beforefragment="false" class="com.example.application.processors.CopyPerspectiveSnippetProcessor"/>
</extension>
Reset the perspective as normal. You will also want to set the perspective stack and the current perspective to visible, as these can sometimes be set to invisible. A sample handler might look like:
import org.eclipse.e4.core.di.annotations.Execute;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.ui.advanced.MPerspectiveStack;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import org.eclipse.ui.PlatformUI;
public class ResetPerspectiveHandler {
private static final String MAIN_PERSPECTIVE_STACK_ID = "MainPerspectiveStack";
#Execute
public void execute(EModelService modelService, MApplication application) {
MPerspectiveStack perspectiveStack = (MPerspectiveStack) modelService.find(MAIN_PERSPECTIVE_STACK_ID, application);
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().resetPerspective();
perspectiveStack.getSelectedElement().setVisible(true);
perspectiveStack.setVisible(true);
}
}

Reset perspective (when you lunch e4 application without clearing work space, when you switch other perspective to your perceptive).
Step 1: Add a add-on in your model fragment at application level.
Step 2: Create Add-on class and implement EventHandler
Step 3: add following code in the class.
public class ResetPrespectiveAddOn implements EventHandler {
private static final String MY_PERSPECTIVE_ID = "myPrespectiveId";
#Inject
private IEventBroker broker;
#PostConstruct
public void loadPrespective() {
broker.subscribe(UIEvents.ElementContainer.TOPIC_SELECTEDELEMENT, this);
}
#SuppressWarnings("restriction")
#Override
public void handleEvent(Event event) {
//UIEvents.EventTags.ELEMENT is trigger for all UI activity
Object property = event.getProperty(UIEvents.EventTags.ELEMENT);
if (!(property instanceof PerspectiveStackImpl)) {
return;
}
// Reset perspective logic .
IEclipseContext serviceContext = E4Workbench.getServiceContext();
final IEclipseContext appContext = (IEclipseContext) serviceContext.getActiveChild();
EModelService modelService = appContext.get(EModelService.class);
MApplication application = serviceContext.get(MApplication.class);
MWindow mWindow = application.getChildren().get(0);
PerspectiveStackImpl perspectiveStack = (PerspectiveStackImpl) property;
List<MPerspective> children = perspectiveStack.getChildren();
for (MPerspective myPerspective : children) {
if (myPerspective.getElementId().equals(MY_PERSPECTIVE_ID)) {
//find active perspective
MPerspective activePerspective = modelService.getActivePerspective(mWindow);
if(activePerspective.getElementId().equals(MY_PERSPECTIVE_ID))
//Reseting perspective e3 way
PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().resetPerspective();
// till now there is no direct e4 way to reset perspective
// but u can Add and remove e4 perspective with this code code
EPartService partService = serviceContext.get(EPartService.class);
MPerspectiveStack perspectiveStack = (MPerspectiveStack) (MElementContainer<?>) activePerspective.getParent();
int indexOf = perspectiveStack.getChildren().indexOf(activePerspective);
perspectiveStack.getChildren().remove(indexOf);
perspectiveStack.getChildren().add(myPerspective);
partService.switchPerspective(myPerspective);
}
}
}}

Related

Own Application Class in RCP is not called

I develop a Eclipse RCP Client with the 2019-06 Eclipse Framework.
My aim is it to override the IDEApplication class from the eclipse core, because I would like to force the workspace choose prompt to pop up at every start. In the eclipse class are some coditions which creates problems in my application. This is the reason why I want to override the class. My problem is now that my application class is not called at the startup of the product.
This is my application class.
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.swt.widgets.Display;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.PlatformUI;
/**
* This class controls all aspects of the application's execution
*/
public class Application implements IApplication {
/*
* (non-Javadoc)
*
* #see org.eclipse.equinox.app.IApplication#start(org.eclipse.equinox.app.IApplicationContext)
*/
#Override
public Object start(IApplicationContext context) throws Exception {
Display display = PlatformUI.createDisplay();
Location instanceLoc = Platform.getInstanceLocation();
boolean isWorkspaceSelected = false;
try {
URL url = new File(System.getProperty(“user.home”), “workspace”).toURI().toURL();
ChooseWorkspaceData data = new ChooseWorkspaceData(url);
ChooseWorkspaceDialog dialog = new ChooseWorkspaceDialog(display.getActiveShell(), data, true, true);
dialog.prompt(true);
String selection = data.getSelection();
if (selection != null) {
isWorkspaceSelected = true;
data.writePersistedData();
url = new File(selection).toURI().toURL();
instanceLoc.set(url, false);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
try {
if (isWorkspaceSelected) {
int returnCode = PlatformUI.createAndRunWorkbench(display, new ApplicationWorkbenchAdvisor());
if (returnCode == PlatformUI.RETURN_RESTART)
return IApplication.EXIT_RESTART;
}
return IApplication.EXIT_OK;
} finally {
display.dispose();
}
}
/*
* (non-Javadoc)
*
* #see org.eclipse.equinox.app.IApplication#stop()
*/
#Override
public void stop() {
if (!PlatformUI.isWorkbenchRunning())
return;
final IWorkbench workbench = PlatformUI.getWorkbench();
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
#Override
public void run() {
if (!display.isDisposed())
workbench.close();
}
});
}
}
Now I have two questions.
If I debug my application this class is never in the callstack. What do I have to do that this class is started ?
Is there a other way to force the prompt for choosing a workspace location at the start of the application than to override this class ?
My main problem is that the original class of the core has the following condition:
if workspace is not set -> create dialog if workspace is already set -> dont create the dialog.
Unfortunatly in my application the workspace location is already set in the internal of eclipse beofre the core of eclipse is loaded.
I have already tried to change the start order of the plugins but that hasn´t helped.

How to manage command parameters when using programmatic menu

I'm using a MenuContribution to feed a menu entry, implementing a feature like the "switch workspace" in E3.
In a dynamic menu contribution, i'm building a 3 item list of most recent opened projects followed by the "Other.." entry.
graphically, i'm done, the 3 list, separator and "other.." menu elements are showing up.
But in the case of most recent project, i have to dynamically pass the project name/Path to the handler which consume the selection event.
below is a code similar to what i have in the menu contribution that creates one of the 3 recent project item :
#AboutToShow
public void aboutToShow(List<MMenuElement> items, MApplication application) {
MHandledMenuItem dynamicItem = modelService.createModelElement(MHandledMenuItem.class);
dynamicItem.setLabel(projectName);
dynamicItem.setContributorURI("platform:/plugin/com.acme");
MCommand command = modelService.createModelElement(MCommand.class);
command.setElementId(LOAD_PROJECT_COMMAND_ID);
MCommandParameter commandParam = modelService.createModelElement(MCommandParameter.class);
commandParam.setElementId(PROJECT_NAME_PARAMETER_ID);
commandParam.setName(PROJECT_NAME_PARAMETER_ID);
command.getParameters().add(commandParam);
// one of the 3 last used projects
String projectName = "foo";
dynamicItem.setCommand(command);
items.add(dynamicItem);
}
where LOAD_PROJECT_COMMAND_ID and PROJECT_NAME_PARAMETER_ID are e4xmi command and command parameter id.
I wonder how i can put projectName in the command to be able to get it back in the associated handler, which contains something like :
#Execute
public void execute(ParameterizedCommand command) {
[...]
}
Note : I read Lars tutorial about menus but did not found solution in there
--- EDIT : full contribution code ---
import java.util.Collections;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.eclipse.e4.core.commands.ECommandService;
import org.eclipse.e4.ui.di.AboutToShow;
import org.eclipse.e4.ui.model.application.MApplication;
import org.eclipse.e4.ui.model.application.commands.MCommand;
import org.eclipse.e4.ui.model.application.commands.MParameter;
import org.eclipse.e4.ui.model.application.ui.menu.MDirectMenuItem;
import org.eclipse.e4.ui.model.application.ui.menu.MHandledMenuItem;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuElement;
import org.eclipse.e4.ui.model.application.ui.menu.MMenuSeparator;
import org.eclipse.e4.ui.workbench.modeling.EModelService;
import com.acme.model.platypus.extractionresult.CampaignResultProvider;
#SuppressWarnings("restriction")
public class SwitchProjectMenuContribution {
private static final String NEW_PROJECT = "Other...";
private static final String LOAD_PROJECT_COMMAND_ID = "gui.rcp4.command.loadProjectCommand";
private static final String PROJECT_NAME_PARAMETER_ID = "gui.rcp4.command.loadProjectCommand.projectName";
#Inject
CampaignResultProvider campaignResultProvider;
#Inject
private EModelService modelService;
#Inject
ECommandService commandService;
private MDirectMenuItem otherProjectItem;
private MMenuSeparator separatorItem;
private MCommand loadProjectCommand;
#SuppressWarnings("unchecked")
#PostConstruct
public void initialize(MApplication application) {
loadProjectCommand = (MCommand) modelService
.findElements(application, LOAD_PROJECT_COMMAND_ID, MCommand.class, Collections.EMPTY_LIST).get(0);
otherProjectItem = modelService.createModelElement(MDirectMenuItem.class);
otherProjectItem.setLabel(NEW_PROJECT);
otherProjectItem.setContributorURI("platform:/plugin/com.acme.gui.rcp4");
otherProjectItem.setContributionURI(
"bundleclass://com.acme.gui.rcp4/com.acme.gui.rcp4.handlers.OtherProjecthandler");
separatorItem = modelService.createModelElement(MMenuSeparator.class);
}
#AboutToShow
public void aboutToShow(List<MMenuElement> items, MApplication application) {
String[] lastProject = campaignResultProvider.getLastUsed();
MMenuElement newEntry;
for (String projectName : lastProject) {
newEntry = createExistingProjectEntry(projectName);
items.add(newEntry);
}
if (lastProject.length > 0) {
items.add(separatorItem);
}
items.add(otherProjectItem);
}
private MHandledMenuItem createExistingProjectEntry(String projectPath) {
MHandledMenuItem dynamicItem = modelService.createModelElement(MHandledMenuItem.class);
dynamicItem.setLabel(projectPath);
dynamicItem.setContributorURI("platform:/plugin/com.acme.gui.rcp4");
MParameter commandParam = modelService.createModelElement(MParameter.class);
commandParam.setName("projectName");
commandParam.setElementId(PROJECT_NAME_PARAMETER_ID);
commandParam.setValue(projectPath);
dynamicItem.getParameters().add(commandParam);
dynamicItem.setCommand(loadProjectCommand);
return dynamicItem;
}
}
You add the parameter value to the MHandledMenuItem not the command.
Use a MParameter and call the setName and setValue methods to set the name (must match the parameter name in the command) and value (the project name in your case).
Add the MParameter to the MHandledMenuItem.getParameters() list.
Note: You should only define the command and command parameter once, not every time aboutToShow is called (so that should probably be in the e4xmi file).

delete Treenode not removed

I am developing in Visual Studio 2012 web interface. When I remove a parent node it removes correctly, but when I try to remove a child node the node stays and does not seem to get removed. Both methods shows the same result.
Tree1.Nodes.Remove(e.Node);
This is a postback method removing the node with e as FineUI.TreeCommandEventArgs.
Tree1.Nodes.Remove(Tree1.SelectedNode);
This is another method to remove the node. There is no update or refresh method to refresh the tree. Both of which cannot delete a child node.
Another question would be that I want to update the database based on the SelectedNode, the SelectedNodeID contains a string with the ID value, but it exist in a form like fnode1 where I only want the integer value at the end. I want to know how to get just the integer value so I can delete the selected node from the database.
what u need to do is you need to take DefaultNode from Tree and then u have to Remove it. see this.
DefaultMutableTreeNode defaultMutableTreeNode = new DefaultMutableTreeNode(node_vervesystems);
model.removeNodeFromParent(defaultMutableTreeNode);
that will Work.
Here the Example for the same.
import javax.swing.JFrame;
import javax.swing.*;
import javax.swing.tree.*;
import java.awt.*;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
/*
* To change this license header, choose License Headers in Project Properties.
* To change this template file, choose Tools | Templates
* and open the template in the editor.
*/
/**
*
* #author kishan
*/
public class JTreeRemoveNode extends JFrame{
public JTreeRemoveNode() throws HeadlessException {
initializeUI();
}
private void initializeUI() {
setSize(200, 400);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DefaultMutableTreeNode root = new DefaultMutableTreeNode("Address Book");
String[] names = new String[] {"Alice", "Bob", "Carol", "Mallory"};
for (String name : names) {
DefaultMutableTreeNode node = new DefaultMutableTreeNode(name);
root.add(node);
}
final JTree tree = new JTree(root);
JScrollPane pane = new JScrollPane(tree);
pane.setPreferredSize(new Dimension(200, 400));
JButton removeButton = new JButton("Remove");
removeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
DefaultTreeModel model = (DefaultTreeModel) tree.getModel();
TreePath[] paths = tree.getSelectionPaths();
for (TreePath path : paths) {
DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
if (node.getParent() != null) {
model.removeNodeFromParent(node);
}
}
}
});
getContentPane().setLayout(new BorderLayout());
getContentPane().add(tree, BorderLayout.CENTER);
getContentPane().add(removeButton, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new JTreeRemoveNode().setVisible(true);
}
});
}
}
hope that will help.

Is there a way to have Eclipse flash its taskbar icon once a time consuming task finishes?

I often minimize Eclipse to read or work on something else for a few minutes while I wait for it to do something (e.g., run a large JUnit test suite, synchronize a huge number of files with a repo, run a long Ant build, etc.). I have to check back every 30 seconds or so to see if it's finished yet. I would like Eclipse to alert me, preferably by blinking its taskbar icon, after it finishes a time consuming operation. Are there any settings or plugins that can make this happen?
I believe is you have Mylyn installed, this should be enabled by default for Windows 7. See here and here. Regarding the post-build actions, I do not know of any existing Eclipse plugins that do this. However, I have not exhaustively searched the marketplace. However, this could be accomplished with existing Eclipse APIs but it would require someone to author a new Eclipse plugin.
The Eclipse Platform jobs framework has an API called IJobManager. A developer could write a new Eclipse plugin that could use this API to listen for job changes and do the following:
Create an eclipse plugin, register a listener to IJobManager on startup.
Once any interesting job is completed, it could fire off some external task/script using normal java process execution API in the JDK
This all could be accomplished in one Java file, probably less than 500 lines long.
You could use this template to setup a basic Eclipse plugin project including build system and have it built and ready to install into your existing Eclipse.
Update I just found a maven archetype for building eclipse plugins with tycho here. It would be my recommendation for someone new to building an eclipse feature/updatesite.
You can create a new plugin project and create this kind of functionality for yourself. The
IJobchangeListener from the Eclipse Jobs API is probably very interesting for you.
The IJobChangeListener is an interface where you can receive notifications for the different type of job states.
I have created a class called JobListener which adds the IJobchangeListener to the JobManager. With the action SampleAction you can register or unregister the listener. that means, if the listener is registered and your application is minimized you will be notified with a MessageDialog (no blinking taskbar).
I found a link where someone made his swing application blink. This functionality should be included in the method public void done(final IJobChangeEvent event). I haven't done this in my test class.
You can also get additional information about the Job with
event.getJob();
Here you are able to check the Job name:
String jobName = event.getJob().getName();
The name of the Job is human readable, for example "Collecting garbage", "Update for Decoration Completion", "Building workspace", etc.
The JobListener class.
/**
* A job listener which may be added to a job manager
*/
public class JobListener {
private MyJobListener listener = null;
private IWorkbenchWindow window = null;
private boolean active = false;
public JobListener(IWorkbenchWindow window) {
this.window = window;
}
/**
* register the job listener
*/
public void register() {
listener = new MyJobListener(window);
IJobManager jobMan = Job.getJobManager();
jobMan.addJobChangeListener(listener);
active = true;
}
/**
* unregister the job listener
*/
public void unregister() {
IJobManager jobMan = Job.getJobManager();
jobMan.removeJobChangeListener(listener);
active = false;
}
public boolean isActive() {
return active;
}
class MyJobListener implements IJobChangeListener {
private IWorkbenchWindow window;
public MyJobListener(IWorkbenchWindow window) {
this.window = window;
}
#Override
public void sleeping(IJobChangeEvent event) {
}
#Override
public void scheduled(IJobChangeEvent event) {
}
#Override
public void running(IJobChangeEvent event) {
}
#Override
public void done(final IJobChangeEvent event) {
window.getShell().getDisplay().asyncExec(new Runnable() {
#Override
public void run() {
if(window.getShell().getMinimized()) {
MessageDialog.openInformation(
window.getShell(),
"Test",
"Job " + event.getJob().getName() + " done.");
}
}
});
}
#Override
public void awake(IJobChangeEvent event) {
}
#Override
public void aboutToRun(IJobChangeEvent event) {
System.out.println("About to run: " + event.getJob().getName());
}
}
}
I called this class from a class called SampleAction.java
public class SampleAction implements IWorkbenchWindowActionDelegate {
private IWorkbenchWindow window;
private JobListener listener;
/**
* The constructor.
*/
public SampleAction() {
}
public void run(IAction action) {
if(listener.isActive()) {
listener.unregister();
MessageDialog.openInformation(
window.getShell(),
"Lrt",
"Unregistered");
}
else {
listener.register();
MessageDialog.openInformation(
window.getShell(),
"Lrt",
"Registered");
}
}
public void selectionChanged(IAction action, ISelection selection) {
}
public void dispose() {
}
public void init(IWorkbenchWindow window) {
this.window = window;
this.listener = new JobListener(window);
}
You can get started with eclipse plugin development by creating a new plugin project:
File > New > Project > Plugin Project
I used the Hello World plugin project template to test the code above.

Render view based on another view in Eclipse plugin

I am developing an Eclipse plug-in that has currently 2 views. In my first view I have a list of connections displayed in a TableViewer (name and connection status).In my second view I want to load the tables in a database (the connection). This loading will be done by clicking a menu item on a connection ("view details"). These tables will be displayed in a TreeViewer because they can also have children. I have tried to do it this way:
My View class:
public class DBTreeView extends ViewPart {
private TreeViewer treeViewer;
private Connection root = null;
public DBTreeView() {
Activator.getDefault().setDbTreeView(this);
}
public void createPartControl(Composite parent) {
treeViewer = new TreeViewer(parent);
treeViewer.setContentProvider(new DBTreeContentProvider());
treeViewer.setLabelProvider(new DBTreeLabelProvider());
}
public void setInput(Connection conn){
root = conn;
treeViewer.setInput(root);
treeViewer.refresh();
}
}
I made a setInput method that is called from the action registered with the menu item in the connections view with the currently selected connection as argument:
MViewContentsAction class:
public void run(){
selectedConnection = Activator.getDefault().getConnectionsView().getSelectedConnection();
Activator.getDefault().getDbTreeView().setInput(selectedConnection);
}
In my ContentProvider class:
public Object[] getChildren(Object arg0) {
if (arg0 instanceof Connection){
return ((Connection) arg0).getTables().toArray();
}
return EMPTY_ARRAY;
}
where EMPTY_ARRAY is an...empty array
The problem I'm facing is that when in debug mode, this piece of code is not executed somehow:
Activator.getDefault().getDbTreeView().setInput(selectedConnection);
And also nothing happens in the tree view when clicking the menu item. Any ideas?
Thank you
Huh. Ok, what you're doing here is.. not really the right way. What you should be doing is registering your TableViewer as a selection provider.
getSite().setSelectionProvider(tableViewer);
Then, define a selection listener and add it to the view with the tree viewer like this:
ISelectionListener listener = new ISelectionListener() {
public void selectionChanged(IWorkbenchPart part, ISelection sel) {
if (!(sel instanceof IStructuredSelection))
return;
IStructuredSelection ss = (IStructuredSelection) sel;
// rest of your code dealing with checking whether selection is what is
//expected and if it is, setting it as an input to
//your tree viewer
}
};
public void createPartControl(Composite parent) {
getSite().getPage().addSelectionListener(listener);
}
Now your tree viewer's input will be changed according to what is selected in the table viewer (btw, don't forget to call treeviewer.refresh() after you set new input).
See an example here.