From 8202faca69c45f894cb3b73f1a7cfa9f250c168d Mon Sep 17 00:00:00 2001 From: konsoletyper Date: Sun, 14 Sep 2014 20:08:31 +0400 Subject: [PATCH] Add main class selection in the settings of a project --- .../teavm-eclipse-plugin/META-INF/MANIFEST.MF | 1 + teavm-eclipse/teavm-eclipse-plugin/plugin.xml | 12 +- .../org/teavm/eclipse/TeaVMEclipsePlugin.java | 22 ++- .../eclipse/ui/MainClassSelectionDialog.java | 146 ++++++++++++++++++ .../eclipse/ui/TeaVMProjectPropertyPage.java | 17 +- .../ui/TeaVMProjectPropertyWidget.java | 127 ++++++++++++--- 6 files changed, 292 insertions(+), 33 deletions(-) create mode 100644 teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/MainClassSelectionDialog.java diff --git a/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF b/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF index b12c1d49a..23396ace7 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF +++ b/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF @@ -54,3 +54,4 @@ Bundle-ClassPath: ., lib/websocket-server-9.2.1.v20140609.jar, lib/websocket-servlet-9.2.1.v20140609.jar Export-Package: org.teavm.eclipse.debugger +Bundle-ActivationPolicy: lazy diff --git a/teavm-eclipse/teavm-eclipse-plugin/plugin.xml b/teavm-eclipse/teavm-eclipse-plugin/plugin.xml index ec6c9a8e6..1d25682f8 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/plugin.xml +++ b/teavm-eclipse/teavm-eclipse-plugin/plugin.xml @@ -52,9 +52,13 @@ - + + + + + + + - \ No newline at end of file + diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMEclipsePlugin.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMEclipsePlugin.java index afe47a4ee..06b20a7e4 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMEclipsePlugin.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMEclipsePlugin.java @@ -15,22 +15,20 @@ */ 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 */ -public class TeaVMEclipsePlugin extends Plugin { +public class TeaVMEclipsePlugin extends AbstractUIPlugin { public static final String ID = "org.teavm.eclipse"; - - public static final String NATURE_ID = "org.teavm.eclipse.nature"; - + public static final String NATURE_ID = ID + ".nature"; + public static final String MAIN_METHOD_DIALOG_ID = ID + ".dialogs.mainMethod"; private static TeaVMEclipsePlugin defaultInstance; - static { - } - public TeaVMEclipsePlugin() { defaultInstance = this; } @@ -38,4 +36,12 @@ public class TeaVMEclipsePlugin extends Plugin { public static TeaVMEclipsePlugin getDefault() { 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)); + } } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/MainClassSelectionDialog.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/MainClassSelectionDialog.java new file mode 100644 index 000000000..666b1783b --- /dev/null +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/MainClassSelectionDialog.java @@ -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 + */ +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() { + @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 types = new HashSet<>(); + + public Set 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()); + } + } + } +} diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyPage.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyPage.java index c1ba8eb0a..5dd75c37e 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyPage.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyPage.java @@ -1,10 +1,15 @@ package org.teavm.eclipse.ui; 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.Control; import org.eclipse.ui.IWorkbenchPropertyPage; +import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PropertyPage; +import org.teavm.eclipse.TeaVMEclipsePlugin; /** * @@ -16,7 +21,17 @@ public class TeaVMProjectPropertyPage extends PropertyPage implements IWorkbench @Override protected Control createContents(Composite 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; } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyWidget.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyWidget.java index dd71da014..f296e6889 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyWidget.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyWidget.java @@ -4,16 +4,27 @@ import java.lang.reflect.InvocationTargetException; import java.util.Arrays; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.runtime.CoreException; 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.ProgressMonitorDialog; +import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.jface.operation.IRunnableWithProgress; 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.RowData; +import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; 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; /** @@ -22,6 +33,10 @@ import org.teavm.eclipse.TeaVMEclipsePlugin; */ public class TeaVMProjectPropertyWidget extends Composite { private Button natureButton; + private Text mainClassField; + private Button mainClassChooseButton; + private IJavaProject javaProject; + private IRunnableContext runnableContext; public TeaVMProjectPropertyWidget(Composite parent) { super(parent, SWT.NONE); @@ -31,22 +46,84 @@ public class TeaVMProjectPropertyWidget extends Composite { setLayout(layout); natureButton = new Button(this, SWT.CHECK); 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) { try { 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); } } - 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) { try { if (natureButton.getSelection()) { @@ -58,17 +135,20 @@ public class TeaVMProjectPropertyWidget extends Composite { removeNature(project); } } + ProjectScope scope = new ProjectScope(project); + IEclipsePreferences preferences = scope.getNode(TeaVMEclipsePlugin.ID); + preferences.put("mainClass", mainClassField.getText().trim()); + preferences.flush(); return true; - } catch (CoreException e) { + } catch (CoreException | BackingStoreException e) { reportError(e); return false; } } private void addNature(final IProject project) { - ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(getShell()); try { - progressDialog.run(false, true, new IRunnableWithProgress() { + runnableContext.run(false, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { @@ -86,24 +166,25 @@ public class TeaVMProjectPropertyWidget extends Composite { } catch (InterruptedException e) { reportError(e); } catch (InvocationTargetException e) { - reportError(e.getTargetException()); + return; } } private void removeNature(final IProject project) { - ProgressMonitorDialog progressDialog = new ProgressMonitorDialog(getShell()); try { - progressDialog.run(false, true, new IRunnableWithProgress() { + runnableContext.run(false, true, new IRunnableWithProgress() { @Override public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { try { - String[] natureIds = project.getDescription().getNatureIds(); + IProjectDescription projectDescription = project.getDescription(); + String[] natureIds = projectDescription.getNatureIds(); String[] newNatureIds = new String[natureIds.length - 1]; for (int i = 0; i < natureIds.length; ++i) { - if (natureIds.equals(TeaVMEclipsePlugin.NATURE_ID)) { - System.arraycopy(natureIds, 0, newNatureIds, 0, i - 1); + if (natureIds[i].equals(TeaVMEclipsePlugin.NATURE_ID)) { + System.arraycopy(natureIds, 0, newNatureIds, 0, i); System.arraycopy(natureIds, i + 1, newNatureIds, i, newNatureIds.length - i); - project.getDescription().setNatureIds(newNatureIds); + projectDescription.setNatureIds(newNatureIds); + project.setDescription(projectDescription, monitor); break; } } @@ -115,7 +196,13 @@ public class TeaVMProjectPropertyWidget extends Composite { } catch (InterruptedException e) { reportError(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); + } }