diff --git a/teavm-eclipse/teavm-eclipse-feature/feature.xml b/teavm-eclipse/teavm-eclipse-feature/feature.xml index cb4c923ff..edc65be85 100644 --- a/teavm-eclipse/teavm-eclipse-feature/feature.xml +++ b/teavm-eclipse/teavm-eclipse-feature/feature.xml @@ -222,7 +222,7 @@ */ public class PreferencesBasedTeaVMProjectSettings implements TeaVMProjectSettings { + public static final String ENABLED = "enabled"; public static final String MAIN_CLASS = "mainClass"; public static final String TARGET_DIRECTORY = "targetDirectory"; - private IEclipsePreferences preferences; + public static final String TARGET_FILE_NAME = "targetFileName"; + public static final String MINIFYING = "minifying"; + public static final String INCREMENTAL = "incremental"; + public static final String CACHE_DIRECTORY = "cacheDirectory"; + public static final String SOURCE_MAPS = "sourceMaps"; + public static final String DEBUG_INFORMATION = "debugInformation"; + public static final String PROPERTIES = "properties"; + + private static final String NEW_PROFILE_NAME = "New profile"; + private List profiles = new ArrayList<>(); + private Map profileMap = new HashMap<>(); + private IEclipsePreferences globalPreferences; private String projectName; public PreferencesBasedTeaVMProjectSettings(IProject project) { ProjectScope scope = new ProjectScope(project); - preferences = scope.getNode(TeaVMEclipsePlugin.ID); + globalPreferences = scope.getNode(TeaVMEclipsePlugin.ID); projectName = project.getName(); } @Override - public String getMainClass() { - return preferences.get(MAIN_CLASS, ""); + public TeaVMProfile[] getProfiles() { + return profiles.toArray(new TeaVMProfile[profiles.size()]); } @Override - public void setMainClass(String mainClass) { - preferences.put(MAIN_CLASS, mainClass); + public TeaVMProfile getProfile(String name) { + return profileMap.get(name); } @Override - public String getTargetDirectory() { - return preferences.get(TARGET_DIRECTORY, VariablesPlugin.getDefault().getStringVariableManager() - .generateVariableExpression("workspace_loc", projectName)); + public void deleteProfile(TeaVMProfile profile) { + if (profileMap.get(profile.getName()) != profile) { + return; + } + profileMap.remove(profile); + profiles.remove(profile); } @Override - public void setTargetDirectory(String targetDirectory) { - preferences.put(TARGET_DIRECTORY, targetDirectory); + public TeaVMProfile createProfile() { + String name = NEW_PROFILE_NAME; + if (profileMap.containsKey(name)) { + int i = 1; + do { + name = NEW_PROFILE_NAME + " (" + i++ + ")"; + } while (profileMap.containsKey(name)); + } + ProfileImpl profile = new ProfileImpl(); + profile.name = name; + IStringVariableManager varManager = VariablesPlugin.getDefault().getStringVariableManager(); + profile.setEnabled(true); + profile.setTargetDirectory(varManager.generateVariableExpression("workspace_loc", "/" + projectName)); + profile.setTargetFileName("classes.js"); + profile.setMinifying(true); + profile.setIncremental(false); + profile.setCacheDirectory(varManager.generateVariableExpression("workspace_loc", "/" + projectName)); + profile.setSourceMapsGenerated(true); + profile.setDebugInformationGenerated(true); + profiles.add(profile); + profileMap.put(name, profile); + return profile; } @Override public void save() throws CoreException { try { - preferences.flush(); + for (ProfileImpl profile : profiles) { + profile.preferences = globalPreferences.node(profile.name); + profile.save(); + } + for (String key : globalPreferences.childrenNames()) { + if (!profileMap.containsKey(key)) { + globalPreferences.node(key).removeNode(); + } + } + globalPreferences.flush(); } catch (BackingStoreException e) { throw new CoreException(TeaVMEclipsePlugin.makeError(e)); } @@ -56,9 +103,197 @@ public class PreferencesBasedTeaVMProjectSettings implements TeaVMProjectSetting @Override public void load() throws CoreException { try { - preferences.sync(); + globalPreferences.sync(); + for (String nodeName : globalPreferences.childrenNames()) { + ProfileImpl profile = profileMap.get(nodeName); + if (profile == null) { + profile = new ProfileImpl(); + profile.name = nodeName; + profileMap.put(nodeName, profile); + profiles.add(profile); + } + profile.preferences = globalPreferences.node(nodeName); + profile.load(); + } + for (int i = 0; i < profiles.size(); ++i) { + ProfileImpl profile = profiles.get(i); + if (!globalPreferences.nodeExists(profile.name)) { + profiles.remove(i--); + profileMap.remove(profile.name); + } + } } catch (BackingStoreException e) { throw new CoreException(TeaVMEclipsePlugin.makeError(e)); } } + + private class ProfileImpl implements TeaVMProfile { + Preferences preferences; + String name; + private boolean enabled; + private String mainClass; + private String targetDirectory; + private String targetFileName; + private boolean minifying; + private boolean incremental; + private String cacheDirectory; + private boolean sourceMapsGenerated; + private boolean debugInformationGenerated; + private Properties properties = new Properties(); + + @Override + public String getName() { + return name; + } + + @Override + public void setName(String name) { + ProfileImpl existingProfile = profileMap.get(name); + if (existingProfile != null && existingProfile != this) { + throw new IllegalArgumentException("Profile " + name + " already exists"); + } + profileMap.remove(this.name); + this.name = name; + profileMap.put(name, this); + } + + @Override + public boolean isEnabled() { + return enabled; + } + + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + @Override + public String getMainClass() { + return mainClass; + } + + @Override + public void setMainClass(String mainClass) { + this.mainClass = mainClass; + } + + @Override + public String getTargetDirectory() { + return targetDirectory; + } + + @Override + public void setTargetDirectory(String targetDirectory) { + this.targetDirectory = targetDirectory; + } + + @Override + public String getTargetFileName() { + return targetFileName; + } + + @Override + public void setTargetFileName(String targetFileName) { + this.targetFileName = targetFileName; + } + + @Override + public boolean isMinifying() { + return minifying; + } + + @Override + public void setMinifying(boolean minifying) { + this.minifying = minifying; + } + + @Override + public boolean isIncremental() { + return incremental; + } + + @Override + public void setIncremental(boolean incremental) { + this.incremental = incremental; + } + + @Override + public String getCacheDirectory() { + return cacheDirectory; + } + + @Override + public void setCacheDirectory(String cacheDirectory) { + this.cacheDirectory = cacheDirectory; + } + + @Override + public boolean isSourceMapsGenerated() { + return sourceMapsGenerated; + } + + @Override + public void setSourceMapsGenerated(boolean sourceMapsGenerated) { + this.sourceMapsGenerated = sourceMapsGenerated; + } + + @Override + public boolean isDebugInformationGenerated() { + return debugInformationGenerated; + } + + @Override + public void setDebugInformationGenerated(boolean debugInformationGenerated) { + this.debugInformationGenerated = debugInformationGenerated; + } + + @Override + public Properties getProperties() { + return new Properties(properties); + } + + @Override + public void setProperties(Properties properties) { + this.properties = new Properties(properties); + } + + public void load() throws BackingStoreException { + preferences.sync(); + enabled = preferences.getBoolean(ENABLED, true); + mainClass = preferences.get(MAIN_CLASS, ""); + targetDirectory = preferences.get(TARGET_DIRECTORY, ""); + targetFileName = preferences.get(TARGET_FILE_NAME, ""); + minifying = preferences.getBoolean(MINIFYING, true); + incremental = preferences.getBoolean(INCREMENTAL, false); + cacheDirectory = preferences.get(CACHE_DIRECTORY, ""); + sourceMapsGenerated = preferences.getBoolean(SOURCE_MAPS, true); + debugInformationGenerated = preferences.getBoolean(DEBUG_INFORMATION, true); + Preferences propertiesPrefs = preferences.node(PROPERTIES); + propertiesPrefs.sync(); + properties = new Properties(); + for (String key : propertiesPrefs.keys()) { + properties.setProperty(key, propertiesPrefs.get(key, "")); + } + } + + public void save() throws BackingStoreException { + preferences.clear(); + preferences.putBoolean(ENABLED, enabled); + preferences.put(MAIN_CLASS, mainClass); + preferences.put(TARGET_DIRECTORY, targetDirectory); + preferences.put(TARGET_FILE_NAME, targetFileName); + preferences.putBoolean(MINIFYING, minifying); + preferences.putBoolean(INCREMENTAL, incremental); + preferences.put(CACHE_DIRECTORY, cacheDirectory); + preferences.putBoolean(SOURCE_MAPS, sourceMapsGenerated); + preferences.putBoolean(DEBUG_INFORMATION, debugInformationGenerated); + Preferences propertiesPrefs = preferences.node(PROPERTIES); + propertiesPrefs.clear(); + for (Object key : properties.keySet()) { + propertiesPrefs.put((String)key, properties.getProperty((String)key)); + } + propertiesPrefs.flush(); + preferences.flush(); + } + } } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java index b14ad245a..63f33bd08 100644 --- a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMBuilder.java @@ -6,9 +6,8 @@ import java.net.URL; import java.net.URLClassLoader; import java.util.*; import org.eclipse.core.resources.*; -import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.*; +import org.eclipse.core.variables.IStringVariableManager; import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; @@ -26,44 +25,28 @@ import org.teavm.tooling.TeaVMToolException; * @author Alexey Andreev */ public class TeaVMBuilder extends IncrementalProjectBuilder { + private static final int TICKS_PER_PROFILE = 10000; private URL[] classPath; private IContainer[] sourceContainers; private IContainer[] classFileContainers; private Set usedProjects = new HashSet<>(); + private static Map> profileClasses = new WeakHashMap<>(); @Override protected IProject[] build(int kind, Map args, IProgressMonitor monitor) throws CoreException { - if ((kind == AUTO_BUILD || kind == INCREMENTAL_BUILD) && !shouldBuild()) { - System.out.println("Skipping project " + getProject().getName()); - return null; - } TeaVMProjectSettings projectSettings = getProjectSettings(); - projectSettings.load(); - TeaVMTool tool = new TeaVMTool(); - tool.setClassLoader(prepareClassLoader()); - tool.setDebugInformationGenerated(true); - tool.setSourceMapsFileGenerated(true); - String targetDir = projectSettings.getTargetDirectory(); - targetDir = VariablesPlugin.getDefault().getStringVariableManager().performStringSubstitution(targetDir); - tool.setTargetDirectory(new File(targetDir)); - tool.setRuntime(RuntimeCopyOperation.SEPARATE); - tool.setMinifying(false); - tool.setMainClass(projectSettings.getMainClass()); - tool.setProgressListener(new TeaVMEclipseProgressListener(this, monitor, 10000)); + TeaVMProfile profiles[] = getEnabledProfiles(projectSettings); + monitor.beginTask("Running TeaVM", profiles.length * TICKS_PER_PROFILE); try { - monitor.beginTask("Running TeaVM", 10000); - tool.generate(); - removeMarkers(); - if (tool.getDependencyViolations().hasMissingItems()) { - putMarkers(tool.getDependencyViolations()); + prepareClassPath(); + ClassLoader classLoader = new URLClassLoader(classPath, TeaVMBuilder.class.getClassLoader()); + for (TeaVMProfile profile : profiles) { + SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, TICKS_PER_PROFILE); + buildProfile(kind, subMonitor, profile, classLoader); } - TeaVMEclipsePlugin.getDefault().setProjectClasses(getProject(), classesToResources(tool.getClasses())); - if (!monitor.isCanceled()) { - monitor.done(); - } - } catch (TeaVMToolException e) { - throw new CoreException(TeaVMEclipsePlugin.makeError(e)); + } finally { + monitor.done(); sourceContainers = null; classFileContainers = null; classPath = null; @@ -72,6 +55,56 @@ public class TeaVMBuilder extends IncrementalProjectBuilder { return !usedProjects.isEmpty() ? usedProjects.toArray(new IProject[0]) : null; } + private TeaVMProfile[] getEnabledProfiles(TeaVMProjectSettings settings) { + TeaVMProfile[] profiles = settings.getProfiles(); + int sz = 0; + for (int i = 0; i < profiles.length; ++i) { + TeaVMProfile profile = profiles[i]; + if (profile.isEnabled()) { + profiles[sz++] = profile; + } + } + return Arrays.copyOf(profiles, sz); + } + + private void buildProfile(int kind, IProgressMonitor monitor, TeaVMProfile profile, ClassLoader classLoader) + throws CoreException { + if ((kind == AUTO_BUILD || kind == INCREMENTAL_BUILD) && !shouldBuild(profile)) { + return; + } + IStringVariableManager varManager = VariablesPlugin.getDefault().getStringVariableManager(); + TeaVMTool tool = new TeaVMTool(); + tool.setClassLoader(classLoader); + tool.setDebugInformationGenerated(profile.isDebugInformationGenerated()); + tool.setSourceMapsFileGenerated(profile.isSourceMapsGenerated()); + String targetDir = profile.getTargetDirectory(); + tool.setTargetDirectory(new File(varManager.performStringSubstitution(targetDir))); + tool.setTargetFileName(profile.getTargetFileName()); + tool.setRuntime(RuntimeCopyOperation.SEPARATE); + tool.setMinifying(profile.isMinifying()); + tool.setMainClass(profile.getMainClass()); + tool.getProperties().putAll(profile.getProperties()); + tool.setIncremental(profile.isIncremental()); + String cacheDir = profile.getCacheDirectory(); + tool.setCacheDirectory(!cacheDir.isEmpty() ? new File(varManager.performStringSubstitution(cacheDir)) : null); + tool.setProgressListener(new TeaVMEclipseProgressListener(this, monitor, TICKS_PER_PROFILE)); + try { + monitor.beginTask("Running TeaVM", 10000); + tool.generate(); + removeMarkers(); + if (tool.getDependencyViolations().hasMissingItems()) { + putMarkers(tool.getDependencyViolations()); + } else if (!tool.wasCancelled()) { + setClasses(profile, classesToResources(tool.getClasses())); + } + if (!monitor.isCanceled()) { + monitor.done(); + } + } catch (TeaVMToolException e) { + throw new CoreException(TeaVMEclipsePlugin.makeError(e)); + } + } + private Set classesToResources(Collection classNames) { Set resourcePaths = new HashSet<>(); for (String className : classNames) { @@ -86,8 +119,8 @@ public class TeaVMBuilder extends IncrementalProjectBuilder { return resourcePaths; } - private boolean shouldBuild() throws CoreException { - Set classes = TeaVMEclipsePlugin.getDefault().getProjectClasses(getProject()); + private boolean shouldBuild(TeaVMProfile profile) throws CoreException { + Collection classes = getClasses(profile); if (classes.isEmpty()) { return true; } @@ -100,7 +133,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder { return false; } - private boolean shouldBuild(Set classes, IResourceDelta delta) { + private boolean shouldBuild(Collection classes, IResourceDelta delta) { if (classes.contains(delta.getResource().getFullPath().toString())) { return true; } @@ -112,6 +145,18 @@ public class TeaVMBuilder extends IncrementalProjectBuilder { return false; } + private Collection getClasses(TeaVMProfile profile) { + Set classes; + synchronized (profileClasses) { + classes = profileClasses.get(profile); + } + return classes != null ? new HashSet<>(classes) : new HashSet(); + } + + private void setClasses(TeaVMProfile profile, Collection classes) { + profileClasses.put(profile, new HashSet<>(classes)); + } + private void removeMarkers() throws CoreException { getProject().deleteMarkers(TeaVMEclipsePlugin.DEPENDENCY_MARKER_ID, true, IResource.DEPTH_INFINITE); } @@ -249,11 +294,6 @@ public class TeaVMBuilder extends IncrementalProjectBuilder { return TeaVMEclipsePlugin.getDefault().getSettings(getProject()); } - private ClassLoader prepareClassLoader() throws CoreException { - prepareClassPath(); - return new URLClassLoader(classPath, TeaVMBuilder.class.getClassLoader()); - } - private Set getRelatedProjects() throws CoreException { Set projects = new HashSet<>(); Set visited = new HashSet<>(); 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 3c6e5ea7f..2540bb92d 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 @@ -41,7 +41,6 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin { public static final String DEPENDENCY_MARKER_ID = ID + ".dependencyMarker"; private static TeaVMEclipsePlugin defaultInstance; private ConcurrentMap settingsMap = new ConcurrentHashMap<>(); - private Map> projectClasses = new WeakHashMap<>(); public TeaVMEclipsePlugin() { defaultInstance = this; @@ -132,18 +131,4 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin { } } } - - public void setProjectClasses(IProject project, Set classes) { - synchronized (projectClasses) { - projectClasses.put(project, new HashSet<>(classes)); - } - } - - public Set getProjectClasses(IProject project) { - Set classes; - synchronized (projectClasses) { - classes = projectClasses.get(project); - } - return classes != null ? new HashSet<>(classes) : new HashSet(); - } } diff --git a/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProfile.java b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProfile.java new file mode 100644 index 000000000..b87ea810a --- /dev/null +++ b/teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/TeaVMProfile.java @@ -0,0 +1,53 @@ +package org.teavm.eclipse; + +import java.util.Properties; + +/** + * + * @author Alexey Andreev + */ +public interface TeaVMProfile { + String getName(); + + void setName(String name); + + boolean isEnabled(); + + void setEnabled(boolean enabled); + + String getMainClass(); + + void setMainClass(String mainClass); + + String getTargetDirectory(); + + void setTargetDirectory(String targetDirectory); + + String getTargetFileName(); + + void setTargetFileName(String targetFileName); + + boolean isMinifying(); + + void setMinifying(boolean minifying); + + boolean isIncremental(); + + void setIncremental(boolean incremental); + + String getCacheDirectory(); + + void setCacheDirectory(String cacheDirectory); + + boolean isSourceMapsGenerated(); + + void setSourceMapsGenerated(boolean sourceMapsGenerated); + + boolean isDebugInformationGenerated(); + + void setDebugInformationGenerated(boolean debugInformationGenerated); + + Properties getProperties(); + + void setProperties(Properties properties); +} 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 index a5ee047dc..73ab4c041 100644 --- 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 @@ -7,13 +7,13 @@ import org.eclipse.core.runtime.CoreException; * @author Alexey Andreev */ public interface TeaVMProjectSettings { - String getMainClass(); + TeaVMProfile[] getProfiles(); - void setMainClass(String mainClass); + TeaVMProfile getProfile(String name); - String getTargetDirectory(); + void deleteProfile(TeaVMProfile profile); - void setTargetDirectory(String targetDirectory); + TeaVMProfile createProfile(); void save() 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/TeaVMProfileDialog.java similarity index 55% rename from teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProjectPropertyWidget.java rename to teavm-eclipse/teavm-eclipse-plugin/src/main/java/org/teavm/eclipse/ui/TeaVMProfileDialog.java index 374c67687..34d6c4ab7 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/TeaVMProfileDialog.java @@ -4,13 +4,12 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; -import org.eclipse.core.runtime.IStatus; 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.jdt.core.JavaCore; +import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; -import org.eclipse.jface.operation.IRunnableContext; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; @@ -21,58 +20,68 @@ 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.TeaVMProfile; import org.teavm.eclipse.TeaVMProjectSettings; /** * * @author Alexey Andreev */ -public class TeaVMProjectPropertyWidget extends Composite { - private Button natureButton; +public class TeaVMProfileDialog extends Dialog { + private Text nameField; private Text mainClassField; private Button mainClassChooseButton; private Text targetDirectoryField; private Button targetDirectoryWorkspaceButton; private Button targetDirectoryFileSystemButton; + private Text targetFileNameField; + private Button minifyingButton; private IJavaProject javaProject; - private IRunnableContext runnableContext; + private TeaVMProjectSettings settings; + private TeaVMProfile profile; - public TeaVMProjectPropertyWidget(Composite parent) { - super(parent, SWT.NONE); - GridLayout layout = new GridLayout(1, false); - layout.verticalSpacing = 10; - layout.marginWidth = 10; - 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()); - } - }); + public TeaVMProfileDialog(Shell shell, TeaVMProjectSettings settings, TeaVMProfile profile) { + super(shell); + this.settings = settings; + this.profile = profile; + setShellStyle(getShellStyle() | SWT.RESIZE); } - private void updateEnabled(boolean enabled) { - mainClassField.setEnabled(enabled); - mainClassChooseButton.setEnabled(enabled); - targetDirectoryField.setEnabled(enabled); - targetDirectoryWorkspaceButton.setEnabled(enabled); - targetDirectoryFileSystemButton.setEnabled(enabled); + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText("Editing TeaVM profile"); } - 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; + @Override + protected boolean isResizable() { + return true; + } + + @Override + protected Control createDialogArea(Composite parent) { + Composite area = (Composite)super.createDialogArea(parent); + area.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); + Composite container = new Composite(area, SWT.NONE); + container.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true)); + GridLayout layout = new GridLayout(2, false); layout.horizontalSpacing = 5; container.setLayout(layout); + createNameField(container); createMainClassField(container); createTargetDirectoryField(container); + createTargetFileNameField(container); + createMinifyField(container); + load(); + return container; + } + + private void createNameField(Composite container) { + Label label = new Label(container, SWT.NONE); + label.setText("&Name:"); + + nameField = new Text(container, SWT.SINGLE | SWT.BORDER); + nameField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); } private void createMainClassField(Composite container) { @@ -81,9 +90,8 @@ public class TeaVMProjectPropertyWidget extends Composite { Composite row = new Composite(container, SWT.NONE); row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); - GridLayout rowLayout = new GridLayout(); - rowLayout.numColumns = 2; - rowLayout.horizontalSpacing = 2; + GridLayout rowLayout = new GridLayout(2, false); + rowLayout.marginWidth = 2; row.setLayout(rowLayout); mainClassField = new Text(row, SWT.SINGLE | SWT.BORDER); @@ -104,13 +112,12 @@ public class TeaVMProjectPropertyWidget extends Composite { 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; + GridLayout rowLayout = new GridLayout(3, false); + rowLayout.marginWidth = 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)); + targetDirectoryField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); targetDirectoryWorkspaceButton = new Button(row, SWT.PUSH); targetDirectoryWorkspaceButton.setText("Workspace..."); @@ -128,12 +135,27 @@ public class TeaVMProjectPropertyWidget extends Composite { } }); } - public void setJavaProject(IJavaProject javaProject) { - this.javaProject = javaProject; + + private void createTargetFileNameField(Composite container) { + Label label = new Label(container, SWT.NONE); + label.setText("&Target file:"); + + targetFileNameField = new Text(container, SWT.SINGLE | SWT.BORDER); + targetFileNameField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); } - public void setRunnableContext(IRunnableContext runnableContext) { - this.runnableContext = runnableContext; + private void createMinifyField(Composite container) { + minifyingButton = new Button(container, SWT.CHECK); + minifyingButton.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + minifyingButton.setText("generate minified (obfuscated) code"); + } + + public void setProject(IProject project) throws CoreException { + if (project.hasNature(JavaCore.NATURE_ID)) { + this.javaProject = JavaCore.create(project); + } else { + this.javaProject = null; + } } private void chooseMainClass() { @@ -174,59 +196,38 @@ public class TeaVMProjectPropertyWidget extends Composite { } } - public void load(IProject project) { - try { - natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID)); - TeaVMProjectSettings settings = TeaVMEclipsePlugin.getDefault().getSettings(project); - settings.load(); - mainClassField.setText(settings.getMainClass()); - targetDirectoryField.setText(settings.getTargetDirectory()); - updateEnabled(natureButton.getSelection()); - } catch (CoreException e) { - reportError(e); + @Override + protected void okPressed() { + if (save()) { + super.okPressed(); + } else { + MessageBox mbox = new MessageBox(getShell(), SWT.ICON_ERROR); + mbox.setMessage("Name " + nameField.getText() + " already used by another profile"); + mbox.setText("Invalid data supplied"); + mbox.open(); } } - public boolean save(IProject project) { - try { - if (natureButton.getSelection()) { - if (!project.hasNature(TeaVMEclipsePlugin.NATURE_ID)) { - addNature(project); - } - } else { - if (project.hasNature(TeaVMEclipsePlugin.NATURE_ID)) { - removeNature(project); - } - } - TeaVMProjectSettings settings = TeaVMEclipsePlugin.getDefault().getSettings(project); - settings.setMainClass(mainClassField.getText().trim()); - settings.setTargetDirectory(targetDirectoryField.getText()); - settings.save(); - return true; - } catch (CoreException e) { - reportError(e); + private void load() { + nameField.setText(profile.getName()); + mainClassField.setText(profile.getMainClass() != null ? profile.getMainClass() : ""); + targetDirectoryField.setText(profile.getTargetDirectory()); + targetFileNameField.setText(profile.getTargetFileName()); + minifyingButton.setSelection(profile.isMinifying()); + } + + private boolean save() { + String name = nameField.getText().trim(); + TeaVMProfile existingProfile = settings.getProfile(name); + if (existingProfile != null && existingProfile != profile) { return false; } - } - - private void addNature(final IProject project) { - reportStatus(TeaVMEclipsePlugin.getDefault().addNature(runnableContext, project)); - } - - private void removeNature(final IProject project) { - reportStatus(TeaVMEclipsePlugin.getDefault().removeNature(runnableContext, project)); - } - - private void reportError(Throwable e) { - 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); - } + profile.setName(name); + String mainClass = mainClassField.getText().trim(); + profile.setMainClass(!mainClass.isEmpty() ? mainClass : null); + profile.setTargetDirectory(targetDirectoryField.getText()); + profile.setTargetFileName(targetFileNameField.getText().trim()); + profile.setMinifying(minifyingButton.getSelection()); + return true; } } 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 5dd75c37e..22ade39f0 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 @@ -2,42 +2,228 @@ 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.core.runtime.IStatus; +import org.eclipse.jface.dialogs.ErrorDialog; +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.widgets.*; import org.eclipse.ui.IWorkbenchPropertyPage; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PropertyPage; import org.teavm.eclipse.TeaVMEclipsePlugin; +import org.teavm.eclipse.TeaVMProfile; +import org.teavm.eclipse.TeaVMProjectSettings; /** * * @author Alexey Andreev */ public class TeaVMProjectPropertyPage extends PropertyPage implements IWorkbenchPropertyPage { - private TeaVMProjectPropertyWidget widget; + private Button natureButton; + private Table profilesTable; + private Button addProfileButton; + private Button removeProfileButton; + private Button editProfileButton; + private TeaVMProjectSettings settings; + private IProject project; @Override protected Control createContents(Composite parent) { - widget = new TeaVMProjectPropertyWidget(parent); - widget.setRunnableContext(PlatformUI.getWorkbench().getProgressService()); - IProject project = (IProject)getElement().getAdapter(IProject.class); + project = (IProject)getElement().getAdapter(IProject.class); + settings = TeaVMEclipsePlugin.getDefault().getSettings(project); + + Composite container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(1, false); + layout.verticalSpacing = 10; + layout.marginWidth = 10; + container.setLayout(layout); + + natureButton = new Button(container, SWT.CHECK); + natureButton.setText("Enable TeaVM"); + natureButton.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); + + Control profilesContainer = createProfilesContainer(container); + profilesContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + try { - if (project.hasNature(JavaCore.NATURE_ID)) { - IJavaProject javaProject = JavaCore.create(project); - widget.setJavaProject(javaProject); - } + natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID)); } catch (CoreException e) { - TeaVMEclipsePlugin.logError(e); + reportStatus(e.getStatus()); } - widget.load(project); - return widget; + loadProfiles(); + + return container; + } + + private Control createProfilesContainer(Composite parent) { + Composite container = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.numColumns = 2; + layout.verticalSpacing = 3; + layout.horizontalSpacing = 3; + container.setLayout(layout); + + Label caption = new Label(container, SWT.NONE); + caption.setText("Profiles"); + caption.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 2, 1)); + + profilesTable = new Table(container, SWT.BORDER | SWT.V_SCROLL | SWT.CHECK); + profilesTable.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 4)); + profilesTable.setHeaderVisible(true); + profilesTable.setLinesVisible(true); + TableColumn nameColumn = new TableColumn(profilesTable, SWT.LEFT); + nameColumn.setText("Name"); + nameColumn.setWidth(150); + TableColumn pathColumn = new TableColumn(profilesTable, SWT.LEFT); + pathColumn.setText("Target directory"); + pathColumn.setWidth(300); + TableColumn fileColumn = new TableColumn(profilesTable, SWT.LEFT); + fileColumn.setText("Target file"); + fileColumn.setWidth(150); + + addProfileButton = new Button(container, SWT.PUSH); + addProfileButton.setText("Add..."); + addProfileButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + addProfileButton.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + addProfile(); + } + }); + + editProfileButton = new Button(container, SWT.PUSH); + editProfileButton.setText("Edit..."); + editProfileButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + editProfileButton.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + editProfile(); + } + }); + + removeProfileButton = new Button(container, SWT.PUSH); + removeProfileButton.setText("Remove"); + removeProfileButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false)); + removeProfileButton.addSelectionListener(new SelectionAdapter() { + @Override public void widgetSelected(SelectionEvent e) { + deleteProfile(); + } + }); + + return container; + } + + private void loadProfiles() { + try { + settings.load(); + } catch (CoreException e) { + reportStatus(e.getStatus()); + } + for (TeaVMProfile profile : settings.getProfiles()) { + createItemForProfile(profile); + } + } + + private TableItem createItemForProfile(TeaVMProfile profile) { + TableItem item = new TableItem(profilesTable, SWT.NONE); + item.setData(profile); + updateItem(item); + return item; + } + + private void updateItem(TableItem item) { + TeaVMProfile profile = (TeaVMProfile)item.getData(); + item.setText(0, profile.getName()); + item.setText(1, profile.getTargetDirectory()); + item.setText(2, profile.getTargetFileName()); + item.setChecked(profile.isEnabled()); + } + + private void storeItem(TableItem item) { + TeaVMProfile profile = (TeaVMProfile)item.getData(); + profile.setEnabled(item.getChecked()); + } + + private void addProfile() { + try { + TeaVMProfile profile = settings.createProfile(); + TableItem item = createItemForProfile(profile); + storeItem(item); + TeaVMProfileDialog dialog = new TeaVMProfileDialog(getShell(), settings, profile); + dialog.setProject(project); + dialog.open(); + updateItem(item); + } catch (CoreException e) { + reportStatus(e.getStatus()); + } + } + + private void editProfile() { + if (profilesTable.getSelectionCount() != 1) { + return; + } + try { + TableItem item = profilesTable.getSelection()[0]; + TeaVMProfile profile = (TeaVMProfile)item.getData(); + storeItem(item); + TeaVMProfileDialog dialog = new TeaVMProfileDialog(getShell(), settings, profile); + dialog.setProject(project); + dialog.open(); + updateItem(item); + } catch (CoreException e) { + reportStatus(e.getStatus()); + } + } + + private void deleteProfile() { + if (profilesTable.getSelectionCount() != 1) { + return; + } + TableItem item = profilesTable.getSelection()[0]; + settings.deleteProfile((TeaVMProfile)item.getData()); + item.dispose(); } @Override public boolean performOk() { - widget.save((IProject)getElement().getAdapter(IProject.class)); + try { + updateNature(); + settings.save(); + } catch (CoreException e) { + reportStatus(e.getStatus()); + } return super.performOk(); } + + private void updateNature() throws CoreException { + if (natureButton.getSelection()) { + if (!project.hasNature(TeaVMEclipsePlugin.NATURE_ID)) { + addNature(project); + } + } else { + if (project.hasNature(TeaVMEclipsePlugin.NATURE_ID)) { + removeNature(project); + } + } + } + + private void addNature(final IProject project) { + reportStatus(TeaVMEclipsePlugin.getDefault().addNature(PlatformUI.getWorkbench().getProgressService(), + project)); + } + + private void removeNature(final IProject project) { + reportStatus(TeaVMEclipsePlugin.getDefault().removeNature(PlatformUI.getWorkbench().getProgressService(), + project)); + } + + 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); + } + } } diff --git a/teavm-eclipse/teavm-eclipse-updatesite/site.xml b/teavm-eclipse/teavm-eclipse-updatesite/site.xml index 8f988551a..c97737100 100644 --- a/teavm-eclipse/teavm-eclipse-updatesite/site.xml +++ b/teavm-eclipse/teavm-eclipse-updatesite/site.xml @@ -3,7 +3,7 @@ TeaVM update site - +