Add main class selection in the settings of a project

This commit is contained in:
konsoletyper 2014-09-14 20:08:31 +04:00
parent 8351c48e25
commit 8202faca69
6 changed files with 292 additions and 33 deletions

View File

@ -54,3 +54,4 @@ Bundle-ClassPath: .,
lib/websocket-server-9.2.1.v20140609.jar, lib/websocket-server-9.2.1.v20140609.jar,
lib/websocket-servlet-9.2.1.v20140609.jar lib/websocket-servlet-9.2.1.v20140609.jar
Export-Package: org.teavm.eclipse.debugger Export-Package: org.teavm.eclipse.debugger
Bundle-ActivationPolicy: lazy

View File

@ -52,9 +52,13 @@
</runtime> </runtime>
</extension> </extension>
<extension point="org.eclipse.ui.propertyPages"> <extension point="org.eclipse.ui.propertyPages">
<page id="org.teavm.eclipse.projectProperties" name="TeaVM" <page id="org.teavm.eclipse.projectProperties" name="TeaVM" class="org.teavm.eclipse.ui.TeaVMProjectPropertyPage">
objectClass="org.eclipse.core.resources.IProject" <enabledWhen>
class="org.teavm.eclipse.ui.TeaVMProjectPropertyPage"> <or>
<instanceof value="org.eclipse.core.resources.IProject"/>
<instanceof value="org.eclipse.jdt.core.IJavaProject"/>
</or>
</enabledWhen>
</page> </page>
</extension> </extension>
</plugin> </plugin>

View File

@ -15,22 +15,20 @@
*/ */
package org.teavm.eclipse; package org.teavm.eclipse;
import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.ui.plugin.AbstractUIPlugin;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class TeaVMEclipsePlugin extends Plugin { public class TeaVMEclipsePlugin extends AbstractUIPlugin {
public static final String ID = "org.teavm.eclipse"; public static final String ID = "org.teavm.eclipse";
public static final String NATURE_ID = ID + ".nature";
public static final String NATURE_ID = "org.teavm.eclipse.nature"; public static final String MAIN_METHOD_DIALOG_ID = ID + ".dialogs.mainMethod";
private static TeaVMEclipsePlugin defaultInstance; private static TeaVMEclipsePlugin defaultInstance;
static {
}
public TeaVMEclipsePlugin() { public TeaVMEclipsePlugin() {
defaultInstance = this; defaultInstance = this;
} }
@ -38,4 +36,12 @@ public class TeaVMEclipsePlugin extends Plugin {
public static TeaVMEclipsePlugin getDefault() { public static TeaVMEclipsePlugin getDefault() {
return defaultInstance; return defaultInstance;
} }
public static IStatus makeError(Throwable e) {
return new Status(IStatus.ERROR, ID, "Error occured", e);
}
public static void logError(Throwable e) {
getDefault().getLog().log(makeError(e));
}
} }

View File

@ -0,0 +1,146 @@
package org.teavm.eclipse.ui;
import static org.teavm.eclipse.TeaVMEclipsePlugin.MAIN_METHOD_DIALOG_ID;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import org.eclipse.core.runtime.*;
import org.eclipse.jdt.core.*;
import org.eclipse.jdt.core.search.*;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog;
import org.teavm.eclipse.TeaVMEclipsePlugin;
/**
*
* @author Alexey Andreev <konsoletyper@gmail.com>
*/
public class MainClassSelectionDialog extends FilteredItemsSelectionDialog {
private IJavaProject javaProject;
public MainClassSelectionDialog(Shell shell, IJavaProject javaProject) {
super(shell, false);
this.javaProject = javaProject;
setTitle("Searching main class");
LabelProvider labelProvider = new LabelProvider() {
@Override public String getText(Object element) {
return getElementName(element);
}
};
setListLabelProvider(labelProvider);
setDetailsLabelProvider(labelProvider);
}
@Override
protected Control createExtendedContentArea(Composite parent) {
return null;
}
@Override
protected ItemsFilter createFilter() {
return new ItemsFilter() {
@Override public boolean matchItem(Object item) {
IType type = (IType)item;
return type.getTypeQualifiedName().toLowerCase().contains(getPattern().toLowerCase());
}
@Override public boolean isConsistentItem(Object item) {
return item instanceof IType;
}
};
}
@Override
protected void fillContentProvider(AbstractContentProvider contentProvider, ItemsFilter filter,
IProgressMonitor progressMonitor) throws CoreException {
IType[] mainTypes = findMainTypes(progressMonitor);
for (IType type : mainTypes) {
contentProvider.add(type, filter);
}
}
@Override
protected IDialogSettings getDialogSettings() {
IDialogSettings settings = TeaVMEclipsePlugin.getDefault().getDialogSettings();
IDialogSettings section = settings.getSection(MAIN_METHOD_DIALOG_ID);
if (section == null) {
section = settings.addNewSection(MAIN_METHOD_DIALOG_ID);
}
return section;
}
@Override
public String getElementName(Object element) {
IType type = (IType)element;
return getTypeName(type);
}
private String getTypeName(IType type) {
if (type == null) {
return null;
}
StringBuilder sb = new StringBuilder(type.getTypeQualifiedName());
if (type.getPackageFragment() != null) {
sb.append(" in ").append(type.getPackageFragment().getElementName());
}
return sb.toString();
}
@Override
protected Comparator<?> getItemsComparator() {
return new Comparator<IType>() {
@Override public int compare(IType o1, IType o2) {
return getTypeName(o1).compareTo(getTypeName(o2));
}
};
}
@Override
protected IStatus validateItem(Object item) {
return Status.OK_STATUS;
}
private IType[] findMainTypes(IProgressMonitor progressMonitor) {
IJavaSearchScope scope = SearchEngine.createJavaSearchScope(new IJavaProject[] { javaProject },
IJavaSearchScope.SOURCES | IJavaSearchScope.REFERENCED_PROJECTS |
IJavaSearchScope.APPLICATION_LIBRARIES);
SearchPattern pattern = SearchPattern.createPattern("main(String[]) void", IJavaSearchConstants.METHOD,
IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE);
SearchParticipant[] participants = new SearchParticipant[] { SearchEngine.getDefaultSearchParticipant() };
MainClassCollector collector = new MainClassCollector();
try {
new SearchEngine().search(pattern, participants, scope, collector, progressMonitor);
} catch (CoreException e) {
logError(e);
return new IType[0];
}
IType[] foundTypes = collector.getTypes().toArray(new IType[collector.getTypes().size()]);
return foundTypes;
}
private void logError(Throwable e) {
IStatus status = TeaVMEclipsePlugin.makeError(e);
TeaVMEclipsePlugin.getDefault().getLog().log(status);
ErrorDialog.openError(getShell(), "Error", "Error", status);
}
private static class MainClassCollector extends SearchRequestor {
private Set<IType> types = new HashSet<>();
public Set<IType> getTypes() {
return types;
}
@Override
public void acceptSearchMatch(SearchMatch match) throws CoreException {
IMethod method = (IMethod)match.getElement();
if ((method.getFlags() & Flags.AccStatic) != 0) {
types.add(method.getDeclaringType());
}
}
}
}

View File

@ -1,10 +1,15 @@
package org.teavm.eclipse.ui; package org.teavm.eclipse.ui;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IWorkbenchPropertyPage; import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PropertyPage; import org.eclipse.ui.dialogs.PropertyPage;
import org.teavm.eclipse.TeaVMEclipsePlugin;
/** /**
* *
@ -16,7 +21,17 @@ public class TeaVMProjectPropertyPage extends PropertyPage implements IWorkbench
@Override @Override
protected Control createContents(Composite parent) { protected Control createContents(Composite parent) {
widget = new TeaVMProjectPropertyWidget(parent); widget = new TeaVMProjectPropertyWidget(parent);
widget.load((IProject)getElement().getAdapter(IProject.class)); widget.setRunnableContext(PlatformUI.getWorkbench().getProgressService());
IProject project = (IProject)getElement().getAdapter(IProject.class);
try {
if (project.hasNature(JavaCore.NATURE_ID)) {
IJavaProject javaProject = JavaCore.create(project);
widget.setJavaProject(javaProject);
}
} catch (CoreException e) {
TeaVMEclipsePlugin.logError(e);
}
widget.load(project);
return widget; return widget;
} }

View File

@ -4,16 +4,27 @@ import java.lang.reflect.InvocationTargetException;
import java.util.Arrays; import java.util.Arrays;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IProjectDescription;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType;
import org.eclipse.jface.dialogs.ErrorDialog; import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.layout.RowData;
import org.eclipse.swt.layout.RowLayout;
import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.osgi.service.prefs.BackingStoreException;
import org.teavm.eclipse.TeaVMEclipsePlugin; import org.teavm.eclipse.TeaVMEclipsePlugin;
/** /**
@ -22,6 +33,10 @@ import org.teavm.eclipse.TeaVMEclipsePlugin;
*/ */
public class TeaVMProjectPropertyWidget extends Composite { public class TeaVMProjectPropertyWidget extends Composite {
private Button natureButton; private Button natureButton;
private Text mainClassField;
private Button mainClassChooseButton;
private IJavaProject javaProject;
private IRunnableContext runnableContext;
public TeaVMProjectPropertyWidget(Composite parent) { public TeaVMProjectPropertyWidget(Composite parent) {
super(parent, SWT.NONE); super(parent, SWT.NONE);
@ -31,22 +46,84 @@ public class TeaVMProjectPropertyWidget extends Composite {
setLayout(layout); setLayout(layout);
natureButton = new Button(this, SWT.CHECK); natureButton = new Button(this, SWT.CHECK);
natureButton.setText("TeaVM build enabled"); natureButton.setText("TeaVM build enabled");
createOptionsContainer();
natureButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
updateEnabled(natureButton.getSelection());
}
});
}
private void updateEnabled(boolean enabled) {
mainClassField.setEnabled(enabled);
mainClassChooseButton.setEnabled(enabled);
}
private void createOptionsContainer() {
Composite container = new Composite(this, SWT.NONE);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.verticalSpacing = 6;
layout.horizontalSpacing = 6;
container.setLayout(layout);
createMainClassField(container);
}
private void createMainClassField(Composite container) {
Label label = new Label(container, SWT.NONE);
label.setText("Main class:");
Composite row = new Composite(container, SWT.NONE);
RowLayout rowLayout = new RowLayout();
row.setLayout(rowLayout);
rowLayout.type = SWT.HORIZONTAL;
rowLayout.spacing = 3;
mainClassField = new Text(row, SWT.SINGLE | SWT.BORDER);
RowData rowData = new RowData();
rowData.width = 300;
mainClassField.setLayoutData(rowData);
mainClassChooseButton = new Button(row, SWT.PUSH);
mainClassChooseButton.setText("Choose...");
mainClassChooseButton.addSelectionListener(new SelectionAdapter() {
@Override public void widgetSelected(SelectionEvent e) {
chooseMainClass();
}
});
}
private void chooseMainClass() {
MainClassSelectionDialog selectionDialog = new MainClassSelectionDialog(getShell(), javaProject);
if (selectionDialog.open() == MainClassSelectionDialog.OK) {
Object[] result = selectionDialog.getResult();
if (result.length > 0) {
IType type = (IType)result[0];
mainClassField.setText(type.getFullyQualifiedName());
}
}
}
public void setJavaProject(IJavaProject javaProject) {
this.javaProject = javaProject;
}
public void setRunnableContext(IRunnableContext runnableContext) {
this.runnableContext = runnableContext;
} }
public void load(IProject project) { public void load(IProject project) {
try { try {
natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID)); natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID));
} catch (CoreException e) { ProjectScope scope = new ProjectScope(project);
IEclipsePreferences preferences = scope.getNode(TeaVMEclipsePlugin.ID);
preferences.sync();
mainClassField.setText(preferences.get("mainClass", ""));
updateEnabled(natureButton.getSelection());
} catch (CoreException | BackingStoreException e) {
reportError(e); reportError(e);
} }
} }
private void reportError(Throwable e) {
e.printStackTrace();
Status status = new Status(Status.ERROR, TeaVMEclipsePlugin.ID, getToolTipText(), e);
ErrorDialog.openError(getShell(), "Error occured", "Error occured", status);
}
public boolean save(IProject project) { public boolean save(IProject project) {
try { try {
if (natureButton.getSelection()) { if (natureButton.getSelection()) {
@ -58,17 +135,20 @@ public class TeaVMProjectPropertyWidget extends Composite {
removeNature(project); removeNature(project);
} }
} }
ProjectScope scope = new ProjectScope(project);
IEclipsePreferences preferences = scope.getNode(TeaVMEclipsePlugin.ID);
preferences.put("mainClass", mainClassField.getText().trim());
preferences.flush();
return true; return true;
} catch (CoreException e) { } catch (CoreException | BackingStoreException e) {
reportError(e); reportError(e);
return false; return false;
} }
} }
private void addNature(final IProject project) { private void addNature(final IProject project) {
ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(getShell());
try { try {
progressDialog.run(false, true, new IRunnableWithProgress() { runnableContext.run(false, true, new IRunnableWithProgress() {
@Override @Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try { try {
@ -86,24 +166,25 @@ public class TeaVMProjectPropertyWidget extends Composite {
} catch (InterruptedException e) { } catch (InterruptedException e) {
reportError(e); reportError(e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
reportError(e.getTargetException()); return;
} }
} }
private void removeNature(final IProject project) { private void removeNature(final IProject project) {
ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(getShell());
try { try {
progressDialog.run(false, true, new IRunnableWithProgress() { runnableContext.run(false, true, new IRunnableWithProgress() {
@Override @Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try { try {
String[] natureIds = project.getDescription().getNatureIds(); IProjectDescription projectDescription = project.getDescription();
String[] natureIds = projectDescription.getNatureIds();
String[] newNatureIds = new String[natureIds.length - 1]; String[] newNatureIds = new String[natureIds.length - 1];
for (int i = 0; i < natureIds.length; ++i) { for (int i = 0; i < natureIds.length; ++i) {
if (natureIds.equals(TeaVMEclipsePlugin.NATURE_ID)) { if (natureIds[i].equals(TeaVMEclipsePlugin.NATURE_ID)) {
System.arraycopy(natureIds, 0, newNatureIds, 0, i - 1); System.arraycopy(natureIds, 0, newNatureIds, 0, i);
System.arraycopy(natureIds, i + 1, newNatureIds, i, newNatureIds.length - i); System.arraycopy(natureIds, i + 1, newNatureIds, i, newNatureIds.length - i);
project.getDescription().setNatureIds(newNatureIds); projectDescription.setNatureIds(newNatureIds);
project.setDescription(projectDescription, monitor);
break; break;
} }
} }
@ -115,7 +196,13 @@ public class TeaVMProjectPropertyWidget extends Composite {
} catch (InterruptedException e) { } catch (InterruptedException e) {
reportError(e); reportError(e);
} catch (InvocationTargetException e) { } catch (InvocationTargetException e) {
reportError(e.getTargetException()); return;
} }
} }
private void reportError(Throwable e) {
IStatus status = TeaVMEclipsePlugin.makeError(e);
TeaVMEclipsePlugin.getDefault().getLog().log(status);
ErrorDialog.openError(getShell(), "Error occured", "Error occured", status);
}
} }