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.
Related
I try to override the functionality of CDT ResumeAtLine, MoveToLine, RunToLine. For this reason I created a custom SuspendResumeAdapterFactory but it isn't loaded but compiles and runs without error. Do I maybe need a custom adaptableType too?
Here is the content of my plugin.xml.
<extension point="org.eclipse.core.runtime.adapters">
<factory
class="my.package.CustomSuspendResumeAdapterFactory"
adaptableType="org.eclipse.cdt.dsf.ui.viewmodel.IVMContext">
<adapter type="org.eclipse.debug.core.model.ISuspendResume"/>
</factory>
</extension>
And here my CustomSuspendResumeAdapterFactory this class is reconstructed from memory not 100% sure if the syntax is correct, but I think it should be clear to see what I want to do.
package my.package;
import org.eclipse.cdt.dsf.datamodel.DMContexts;
import org.eclipse.cdt.dsf.debug.internal.ui.actions.MoveToLine;
import org.eclipse.cdt.dsf.debug.internal.ui.actions.ResumeAtLine;
import org.eclipse.cdt.dsf.debug.internal.ui.actions.RunToLine;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IContainerDMContext;
import org.eclipse.cdt.dsf.debug.service.IRunControl.IExecutionDMContext;
import org.eclipse.cdt.dsf.ui.viewmodel.datamodel.IDMVMContext;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IAdapterFactory;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.model.ISuspendResume;
public class CustomSuspendResumeAdapterFactory implements IAdapterFactory {
static class SuspendResume implements ISuspendResume, IAdaptable {
private final CustomRunToLine fRunToLine;
private final CustomMoveToLine fMoveToLine;
private final CustomResumeAtLine fResumeAtLine;
SuspendResume(IExecutionDMContext execCtx) {
fRunToLine = new CustomRunToLine(execCtx);
fMoveToLine = new CustomMoveToLine(execCtx);
fResumeAtLine = new CustomResumeAtLine(execCtx);
}
#SuppressWarnings("unchecked")
#Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isInstance(RunToLine.class)) {
System.out.println("CUSTOM RUNTOLINE");
return (T)fRunToLine;
}
if (adapter.isInstance(MoveToLine.class)) {
System.out.println("CUSTOM MOVETOLINE");
return (T)fMoveToLine;
}
if (adapter.isInstance(ResumeToLine.class)) {
System.out.println("CUSTOM RESUMEATLINE");
return (T)fResumeAtLine;
}
return null;
}
#Override
public boolean canResume() { return false; }
#Override
public boolean canSuspend() { return false; }
// This must return true because the platform
// RunToLineActionDelegate will only enable the
// action if we are suspended
#Override
public boolean isSuspended() { return true; }
#Override
public void resume() throws DebugException {}
#Override
public void suspend() throws DebugException {}
}
#SuppressWarnings("unchecked")
#Override
public <T> T getAdapter(Object adaptableObject, Class<T> adapterType) {
if (ISuspendResume.class.equals(adapterType)) {
if (adaptableObject instanceof IDMVMContext) {
IExecutionDMContext execDmc = DMContexts.getAncestorOfType(
((IDMVMContext)adaptableObject).getDMContext(),
IExecutionDMContext.class);
// It only makes sense to RunToLine, MoveToLine or
// ResumeAtLine if we are dealing with a thread, not a container
if (execDmc != null && !(execDmc instanceof IContainerDMContext)) {
return (T)new SuspendResume(execDmc);
}
}
}
return null;
}
#Override
public Class<?>[] getAdapterList() {
return new Class[] { ISuspendResume.class };
}
}
Why your code is not run
You have provided a new adapter factory that converts object types that are already handled. i.e. your plugin.xml says you can convert IVMContext to ISuspendResume. But the DSF plug-in already provides such an adapter factory. If you have a new target type (like IMySpecialRunToLine) you could install a factory for that, it would take IVMContext and convert it to a IMySpecialRunToLine).
Although dated, the Eclipse Corner Article on Adapter Pattern may be useful if this is a new concept.
How to do custom Run To Line implementation
If you want to provide different implementation of Run To Line, you need to provide your own version of org.eclipse.cdt.dsf.debug.service.IRunControl2.runToLine(IExecutionDMContext, String, int, boolean, RequestMonitor). The org.eclipse.cdt.dsf.debug.internal.ui.actions.RunToLine class is simply glue to connect UI features (such as buttons/etc some provided directly, some by the core eclipse debug) to the DSF backend. i.e. if you look at what RunToLine does, all it actually does is get the IRunControl2 service and call runToLine on it.
The way to provider your own implementation of IRunControl2 is override org.eclipse.cdt.dsf.gdb.service.GdbDebugServicesFactory.createRunControlService(DsfSession) and provide your own GdbDebugServicesFactory in your custom launch delegate by overriding org.eclipse.cdt.dsf.gdb.launching.GdbLaunchDelegate.newServiceFactory(ILaunchConfiguration, String)
RunToLine will be triggered when the user select Run To Line from the popup menu in the editor, as per this screenshot:
I have been successful in making a plugin. However now i need that on project creation page i add some more textboxes to get the user information. Also i need to use this information to add into the auto generated .php files made in project directory.
I want to know how can i override the WizardNewProjectCreationPage to add some more textboxes to the already given layout. I am pretty new to plugin development. Here is the code for my custom wizard.
import java.net.URI;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.Wizard;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.INewWizard;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.dialogs.WizardNewProjectCreationPage;
import org.eclipse.ui.wizards.newresource.BasicNewProjectResourceWizard;
import rudraxplugin.pages.MyPageOne;
import rudraxplugin.projects.RudraxSupport;
public class CustomProjectNewWizard extends Wizard implements INewWizard, IExecutableExtension {
private WizardNewProjectCreationPage _pageOne;
protected MyPageOne one;
private IConfigurationElement _configurationElement;
public CustomProjectNewWizard() {
// TODO Auto-generated constructor stub
setWindowTitle("RudraX");
}
#Override
public void init(IWorkbench workbench, IStructuredSelection selection) {
// TODO Auto-generated method stub
}
#Override
public void addPages() {
super.addPages();
_pageOne = new WizardNewProjectCreationPage("From Scratch Project Wizard");
_pageOne.setTitle("From Scratch Project");
_pageOne.setDescription("Create something from scratch.");
addPage(one);
addPage(_pageOne);
}
#Override
public boolean performFinish() {
String name = _pageOne.getProjectName();
URI location = null;
if (!_pageOne.useDefaults()) {
location = _pageOne.getLocationURI();
System.err.println("location: " + location.toString()); //$NON-NLS-1$
} // else location == null
RudraxSupport.createProject(name, location);
// Add this
BasicNewProjectResourceWizard.updatePerspective(_configurationElement);
return true;
}
#Override
public void setInitializationData(IConfigurationElement config,
String propertyName, Object data) throws CoreException {
_configurationElement = config;
// TODO Auto-generated method stub
}
}
Ask for any other code required. Any help is appreciated. Thank You.
Instead of using WizardNewProjectCreationPage directly create a new class extending WizardNewProjectCreationPage and override the createControl method to create new controls:
class MyNewProjectCreationPage extends WizardNewProjectCreationPage
{
#Override
public void createControl(Composite parent)
{
super.createControl(parent);
Composite body = (Composite)getControl();
... create new controls here
}
}
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);
}
}
}}
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.
I have created an eclipse application and a product configuration.
In the product configuration on the "Launching" tab its possible to specify "Program arguments" and "VM Arguments".
Is it possible to access these arguments from the Application class? Currently this class looks like this:
public class Application implements IApplication {
#Override
public Object start(IApplicationContext context) throws Exception {
Map<?, ?> arguments = context.getArguments(); // this is empty!
// This actually does the trick but is a bit ugly - must be parsed
String[] strings = (String[]) context.getArguments()
.get("application.args");
Display display = PlatformUI.createDisplay();
try {
ApplicationWorkbenchAdvisor advisor = new ApplicationWorkbenchAdvisor();
int returnCode = PlatformUI.createAndRunWorkbench(display, advisor);
if (returnCode == PlatformUI.RETURN_RESTART) {
return IApplication.EXIT_RESTART;
} else {
return IApplication.EXIT_OK;
}
} finally {
display.dispose();
}
}
/*
* (non-Javadoc)
*
* #see org.eclipse.equinox.app.IApplication#stop()
*/
#Override
public void stop() {
final IWorkbench workbench = PlatformUI.getWorkbench();
if (workbench == null) {
return;
}
final Display display = workbench.getDisplay();
display.syncExec(new Runnable() {
#Override
public void run() {
if (!display.isDisposed()) {
workbench.close();
}
}
});
}
Are there a better way to extract the application args than:
// This actually does the trick but is a bit ugly
String[] strings = (String[]) context.getArguments()
.get("application.args");
Just
Platform.getCommandLineArgs();
See http://www.vogella.de/blog/2008/06/21/passing-parameters-to-eclipse-rcp-via-the-command-line/ for an example.