diff --git a/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF b/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF index 23396ace7..f2b6ec6b9 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF +++ b/teavm-eclipse/teavm-eclipse-plugin/META-INF/MANIFEST.MF @@ -18,7 +18,8 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.8.0,4.0)", org.eclipse.ui.editors;bundle-version="[3.8.0,4.0.0)", org.eclipse.ui.ide;bundle-version="[3.8.2,4.0.0)", org.eclipse.jdt.ui;bundle-version="[3.8.2,4.0.0)", - org.eclipse.core.filesystem;bundle-version="[1.3.200,1.5.0)" + org.eclipse.core.filesystem;bundle-version="[1.3.200,1.5.0)", + org.eclipse.core.variables;bundle-version="[3.2.600,3.3)" Bundle-ClassPath: ., lib/asm-5.0.1.jar, lib/asm-commons-5.0.1.jar, diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/PreferencesBasedTeaVMProjectSettings.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/PreferencesBasedTeaVMProjectSettings.java new file mode 100644 index 000000000..5fc8793d7 --- /dev/null +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/PreferencesBasedTeaVMProjectSettings.java @@ -0,0 +1,64 @@ +package org.teavm.eclipse; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.ProjectScope; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.variables.VariablesPlugin; +import org.osgi.service.prefs.BackingStoreException; + +/** + * + * @author Alexey Andreev + */ +public class PreferencesBasedTeaVMProjectSettings implements TeaVMProjectSettings { + public static final String MAIN_CLASS = "mainClass"; + public static final String TARGET_DIRECTORY = "targetDirectory"; + private IEclipsePreferences preferences; + private String projectName; + + public PreferencesBasedTeaVMProjectSettings(IProject project) { + ProjectScope scope = new ProjectScope(project); + preferences = scope.getNode(TeaVMEclipsePlugin.ID); + projectName = project.getName(); + } + + @Override + public String getMainClass() { + return preferences.get(MAIN_CLASS, ""); + } + + @Override + public void setMainClass(String mainClass) { + preferences.put(MAIN_CLASS, mainClass); + } + + @Override + public String getTargetDirectory() { + return preferences.get(TARGET_DIRECTORY, VariablesPlugin.getDefault().getStringVariableManager() + .generateVariableExpression("workspace_loc", projectName)); + } + + @Override + public void setTargetDirectory(String targetDirectory) { + preferences.put(TARGET_DIRECTORY, targetDirectory); + } + + @Override + public void save() throws CoreException { + try { + preferences.flush(); + } catch (BackingStoreException e) { + throw new CoreException(TeaVMEclipsePlugin.makeError(e)); + } + } + + @Override + public void load() throws CoreException { + try { + preferences.sync(); + } catch (BackingStoreException e) { + throw new CoreException(TeaVMEclipsePlugin.makeError(e)); + } + } +} 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 06b20a7e4..c7a3fbc94 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,8 +15,18 @@ */ package org.teavm.eclipse; +import java.lang.reflect.InvocationTargetException; +import java.util.Arrays; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IProjectDescription; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; +import org.eclipse.jface.operation.IRunnableContext; +import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.ui.plugin.AbstractUIPlugin; /** @@ -28,6 +38,7 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin { public static final String NATURE_ID = ID + ".nature"; public static final String MAIN_METHOD_DIALOG_ID = ID + ".dialogs.mainMethod"; private static TeaVMEclipsePlugin defaultInstance; + private ConcurrentMap settingsMap = new ConcurrentHashMap<>(); public TeaVMEclipsePlugin() { defaultInstance = this; @@ -44,4 +55,78 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin { public static void logError(Throwable e) { getDefault().getLog().log(makeError(e)); } + + public TeaVMProjectSettings getSettings(IProject project) { + TeaVMProjectSettings settings = settingsMap.get(project); + if (settings == null) { + settings = new PreferencesBasedTeaVMProjectSettings(project); + settingsMap.putIfAbsent(project, settings); + settings = settingsMap.get(project); + } + return settings; + } + + public IStatus addNature(IRunnableContext runnableContext, final IProject project) { + try { + runnableContext.run(false, true, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + addNature(monitor, project); + } catch (CoreException e) { + throw new InvocationTargetException(e); + } + } + }); + return Status.OK_STATUS; + } catch (InterruptedException e) { + return makeError(e); + } catch (InvocationTargetException e) { + return Status.CANCEL_STATUS; + } + } + + public void addNature(IProgressMonitor progressMonitor, IProject project) throws CoreException { + IProjectDescription projectDescription = project.getDescription(); + String[] natureIds = projectDescription.getNatureIds(); + natureIds = Arrays.copyOf(natureIds, natureIds.length + 1); + natureIds[natureIds.length - 1] = TeaVMEclipsePlugin.NATURE_ID; + projectDescription.setNatureIds(natureIds); + project.setDescription(projectDescription, progressMonitor); + } + + public IStatus removeNature(IRunnableContext runnableContext, final IProject project) { + try { + runnableContext.run(false, true, new IRunnableWithProgress() { + @Override + public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { + try { + removeNature(monitor, project); + } catch (CoreException e) { + throw new InvocationTargetException(e); + } + } + }); + return Status.OK_STATUS; + } catch (InterruptedException e) { + return makeError(e); + } catch (InvocationTargetException e) { + return Status.CANCEL_STATUS; + } + } + + public void removeNature(IProgressMonitor progressMonitor, IProject project) throws CoreException { + 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[i].equals(TeaVMEclipsePlugin.NATURE_ID)) { + System.arraycopy(natureIds, 0, newNatureIds, 0, i); + System.arraycopy(natureIds, i + 1, newNatureIds, i, newNatureIds.length - i); + projectDescription.setNatureIds(newNatureIds); + project.setDescription(projectDescription, progressMonitor); + break; + } + } + } } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectNature.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectNature.java index aa734f209..49fa6b52a 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectNature.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectNature.java @@ -28,4 +28,8 @@ public class TeaVMProjectNature implements IProjectNature { public void setProject(IProject project) { this.project = project; } + + public TeaVMProjectSettings getSettings() { + return TeaVMEclipsePlugin.getDefault().getSettings(project); + } } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectSettings.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectSettings.java new file mode 100644 index 000000000..a5ee047dc --- /dev/null +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProjectSettings.java @@ -0,0 +1,21 @@ +package org.teavm.eclipse; + +import org.eclipse.core.runtime.CoreException; + +/** + * + * @author Alexey Andreev + */ +public interface TeaVMProjectSettings { + String getMainClass(); + + void setMainClass(String mainClass); + + String getTargetDirectory(); + + void setTargetDirectory(String targetDirectory); + + void save() throws CoreException; + + void load() throws CoreException; +} 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 f296e6889..fb87cb3c4 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 @@ -1,31 +1,28 @@ package org.teavm.eclipse.ui; -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.resources.IResource; +import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; -import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IType; import org.eclipse.jface.dialogs.ErrorDialog; +import org.eclipse.jface.dialogs.IDialogConstants; 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.GridData; 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.eclipse.swt.widgets.*; +import org.eclipse.ui.dialogs.ElementTreeSelectionDialog; +import org.eclipse.ui.model.WorkbenchContentProvider; +import org.eclipse.ui.model.WorkbenchLabelProvider; +import org.eclipse.ui.views.navigator.ResourceComparator; import org.teavm.eclipse.TeaVMEclipsePlugin; +import org.teavm.eclipse.TeaVMProjectSettings; /** * @@ -35,14 +32,17 @@ public class TeaVMProjectPropertyWidget extends Composite { private Button natureButton; private Text mainClassField; private Button mainClassChooseButton; + private Text targetDirectoryField; + private Button targetDirectoryWorkspaceButton; + private Button targetDirectoryFileSystemButton; private IJavaProject javaProject; private IRunnableContext runnableContext; public TeaVMProjectPropertyWidget(Composite parent) { super(parent, SWT.NONE); GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 12; - layout.marginWidth = 12; + layout.verticalSpacing = 10; + layout.marginWidth = 10; setLayout(layout); natureButton = new Button(this, SWT.CHECK); natureButton.setText("TeaVM build enabled"); @@ -59,30 +59,36 @@ public class TeaVMProjectPropertyWidget extends Composite { private void updateEnabled(boolean enabled) { mainClassField.setEnabled(enabled); mainClassChooseButton.setEnabled(enabled); + targetDirectoryField.setEnabled(enabled); + targetDirectoryWorkspaceButton.setEnabled(enabled); + targetDirectoryFileSystemButton.setEnabled(enabled); } private void createOptionsContainer() { Composite container = new Composite(this, SWT.NONE); + container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); GridLayout layout = new GridLayout(); layout.numColumns = 2; - layout.verticalSpacing = 6; - layout.horizontalSpacing = 6; + layout.horizontalSpacing = 5; container.setLayout(layout); createMainClassField(container); + createTargetDirectoryField(container); } private void createMainClassField(Composite container) { Label label = new Label(container, SWT.NONE); - label.setText("Main class:"); + label.setText("&Main class:"); + Composite row = new Composite(container, SWT.NONE); - RowLayout rowLayout = new RowLayout(); + row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + GridLayout rowLayout = new GridLayout(); + rowLayout.numColumns = 2; + rowLayout.horizontalSpacing = 2; 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); + mainClassField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + mainClassChooseButton = new Button(row, SWT.PUSH); mainClassChooseButton.setText("Choose..."); mainClassChooseButton.addSelectionListener(new SelectionAdapter() { @@ -92,6 +98,44 @@ public class TeaVMProjectPropertyWidget extends Composite { }); } + private void createTargetDirectoryField(Composite container) { + Label label = new Label(container, SWT.NONE); + label.setText("&Target directory:"); + + Composite row = new Composite(container, SWT.NONE); + row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + GridLayout rowLayout = new GridLayout(); + rowLayout.numColumns = 3; + rowLayout.horizontalSpacing = 2; + row.setLayout(rowLayout); + + targetDirectoryField = new Text(row, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); + targetDirectoryField.setData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + targetDirectoryWorkspaceButton = new Button(row, SWT.PUSH); + targetDirectoryWorkspaceButton.setText("Workspace..."); + targetDirectoryWorkspaceButton.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + chooseWorkspaceTargetDirectory(); + } + }); + + targetDirectoryFileSystemButton = new Button(row, SWT.PUSH); + targetDirectoryFileSystemButton.setText("External..."); + targetDirectoryFileSystemButton.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + chooseFileSystemTargetDirectory(); + } + }); + } + public void setJavaProject(IJavaProject javaProject) { + this.javaProject = javaProject; + } + + public void setRunnableContext(IRunnableContext runnableContext) { + this.runnableContext = runnableContext; + } + private void chooseMainClass() { MainClassSelectionDialog selectionDialog = new MainClassSelectionDialog(getShell(), javaProject); if (selectionDialog.open() == MainClassSelectionDialog.OK) { @@ -103,23 +147,42 @@ public class TeaVMProjectPropertyWidget extends Composite { } } - public void setJavaProject(IJavaProject javaProject) { - this.javaProject = javaProject; + private void chooseWorkspaceTargetDirectory() { + ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), new WorkbenchLabelProvider(), + new WorkbenchContentProvider()); + dialog.setTitle("Selecting target directory"); + dialog.setMessage("Please, select a target directory for TeaVM build"); + dialog.setInput(ResourcesPlugin.getWorkspace().getRoot()); + dialog.setComparator(new ResourceComparator(ResourceComparator.NAME)); + if (dialog.open() == IDialogConstants.OK_ID) { + IResource resource = (IResource)dialog.getFirstResult(); + if (resource != null) { + String path = resource.getFullPath().toString(); + String fileLoc = VariablesPlugin.getDefault().getStringVariableManager() + .generateVariableExpression("workspace_loc", path); + targetDirectoryField.setText(fileLoc); + } + } } - public void setRunnableContext(IRunnableContext runnableContext) { - this.runnableContext = runnableContext; + private void chooseFileSystemTargetDirectory() { + String filePath = targetDirectoryField.getText(); + FileDialog dialog = new FileDialog(getShell(), SWT.SAVE); + filePath = dialog.open(); + if (filePath != null) { + targetDirectoryField.setText(filePath); + } } public void load(IProject project) { try { natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID)); - ProjectScope scope = new ProjectScope(project); - IEclipsePreferences preferences = scope.getNode(TeaVMEclipsePlugin.ID); - preferences.sync(); - mainClassField.setText(preferences.get("mainClass", "")); + TeaVMProjectSettings settings = TeaVMEclipsePlugin.getDefault().getSettings(project); + settings.load(); + mainClassField.setText(settings.getMainClass()); + targetDirectoryField.setText(settings.getTargetDirectory()); updateEnabled(natureButton.getSelection()); - } catch (CoreException | BackingStoreException e) { + } catch (CoreException e) { reportError(e); } } @@ -135,74 +198,35 @@ 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(); + TeaVMProjectSettings settings = TeaVMEclipsePlugin.getDefault().getSettings(project); + settings.setMainClass(mainClassField.getText().trim()); + settings.setTargetDirectory(targetDirectoryField.getText()); + settings.save(); return true; - } catch (CoreException | BackingStoreException e) { + } catch (CoreException e) { reportError(e); return false; } } private void addNature(final IProject project) { - try { - runnableContext.run(false, true, new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - try { - IProjectDescription projectDescription = project.getDescription(); - String[] natureIds = projectDescription.getNatureIds(); - natureIds = Arrays.copyOf(natureIds, natureIds.length + 1); - natureIds[natureIds.length - 1] = TeaVMEclipsePlugin.NATURE_ID; - projectDescription.setNatureIds(natureIds); - project.setDescription(projectDescription, monitor); - } catch (CoreException e) { - throw new InvocationTargetException(e); - } - } - }); - } catch (InterruptedException e) { - reportError(e); - } catch (InvocationTargetException e) { - return; - } + reportStatus(TeaVMEclipsePlugin.getDefault().addNature(runnableContext, project)); } private void removeNature(final IProject project) { - try { - runnableContext.run(false, true, new IRunnableWithProgress() { - @Override - public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { - try { - 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[i].equals(TeaVMEclipsePlugin.NATURE_ID)) { - System.arraycopy(natureIds, 0, newNatureIds, 0, i); - System.arraycopy(natureIds, i + 1, newNatureIds, i, newNatureIds.length - i); - projectDescription.setNatureIds(newNatureIds); - project.setDescription(projectDescription, monitor); - break; - } - } - } catch (CoreException e) { - throw new InvocationTargetException(e); - } - } - }); - } catch (InterruptedException e) { - reportError(e); - } catch (InvocationTargetException e) { - return; - } + reportStatus(TeaVMEclipsePlugin.getDefault().removeNature(runnableContext, project)); } private void reportError(Throwable e) { - IStatus status = TeaVMEclipsePlugin.makeError(e); - TeaVMEclipsePlugin.getDefault().getLog().log(status); - ErrorDialog.openError(getShell(), "Error occured", "Error occured", status); + reportStatus(TeaVMEclipsePlugin.makeError(e)); + } + + private void reportStatus(IStatus status) { + if (!status.isOK()) { + TeaVMEclipsePlugin.getDefault().getLog().log(status); + } + if (status.getSeverity() == IStatus.ERROR) { + ErrorDialog.openError(getShell(), "Error occured", "Error occured", status); + } } }