Introduce concept of profiles that contain information about the way to

build project. Several profiles can be assigned to a project.
This commit is contained in:
konsoletyper 2014-09-17 14:42:37 +04:00
parent 700d50b110
commit 91273ddaf7
9 changed files with 682 additions and 182 deletions

View File

@ -222,7 +222,7 @@
</license> </license>
<plugin <plugin
id="teavm-eclipse-plugin" id="org.teavm.eclipse"
os="aix,hpux,linux,macosx,qnx,solaris,win32" os="aix,hpux,linux,macosx,qnx,solaris,win32"
ws="carbon,cocoa,gtk,motif,photon,win32,wpf" ws="carbon,cocoa,gtk,motif,photon,win32,wpf"
arch="ia64,ia64_32,PA_RISC,ppc,sparc,x86,x86_64" arch="ia64,ia64_32,PA_RISC,ppc,sparc,x86,x86_64"

View File

@ -1,53 +1,100 @@
package org.teavm.eclipse; package org.teavm.eclipse;
import java.util.*;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope; import org.eclipse.core.resources.ProjectScope;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.core.variables.VariablesPlugin;
import org.osgi.service.prefs.BackingStoreException; import org.osgi.service.prefs.BackingStoreException;
import org.osgi.service.prefs.Preferences;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class PreferencesBasedTeaVMProjectSettings implements TeaVMProjectSettings { public class PreferencesBasedTeaVMProjectSettings implements TeaVMProjectSettings {
public static final String ENABLED = "enabled";
public static final String MAIN_CLASS = "mainClass"; public static final String MAIN_CLASS = "mainClass";
public static final String TARGET_DIRECTORY = "targetDirectory"; 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<ProfileImpl> profiles = new ArrayList<>();
private Map<String, ProfileImpl> profileMap = new HashMap<>();
private IEclipsePreferences globalPreferences;
private String projectName; private String projectName;
public PreferencesBasedTeaVMProjectSettings(IProject project) { public PreferencesBasedTeaVMProjectSettings(IProject project) {
ProjectScope scope = new ProjectScope(project); ProjectScope scope = new ProjectScope(project);
preferences = scope.getNode(TeaVMEclipsePlugin.ID); globalPreferences = scope.getNode(TeaVMEclipsePlugin.ID);
projectName = project.getName(); projectName = project.getName();
} }
@Override @Override
public String getMainClass() { public TeaVMProfile[] getProfiles() {
return preferences.get(MAIN_CLASS, ""); return profiles.toArray(new TeaVMProfile[profiles.size()]);
} }
@Override @Override
public void setMainClass(String mainClass) { public TeaVMProfile getProfile(String name) {
preferences.put(MAIN_CLASS, mainClass); return profileMap.get(name);
} }
@Override @Override
public String getTargetDirectory() { public void deleteProfile(TeaVMProfile profile) {
return preferences.get(TARGET_DIRECTORY, VariablesPlugin.getDefault().getStringVariableManager() if (profileMap.get(profile.getName()) != profile) {
.generateVariableExpression("workspace_loc", projectName)); return;
}
profileMap.remove(profile);
profiles.remove(profile);
} }
@Override @Override
public void setTargetDirectory(String targetDirectory) { public TeaVMProfile createProfile() {
preferences.put(TARGET_DIRECTORY, targetDirectory); 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 @Override
public void save() throws CoreException { public void save() throws CoreException {
try { 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) { } catch (BackingStoreException e) {
throw new CoreException(TeaVMEclipsePlugin.makeError(e)); throw new CoreException(TeaVMEclipsePlugin.makeError(e));
} }
@ -56,9 +103,197 @@ public class PreferencesBasedTeaVMProjectSettings implements TeaVMProjectSetting
@Override @Override
public void load() throws CoreException { public void load() throws CoreException {
try { 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) { } catch (BackingStoreException e) {
throw new CoreException(TeaVMEclipsePlugin.makeError(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();
}
}
} }

View File

@ -6,9 +6,8 @@ import java.net.URL;
import java.net.URLClassLoader; import java.net.URLClassLoader;
import java.util.*; import java.util.*;
import org.eclipse.core.resources.*; import org.eclipse.core.resources.*;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.IPath; import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IJavaProject;
@ -26,44 +25,28 @@ import org.teavm.tooling.TeaVMToolException;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class TeaVMBuilder extends IncrementalProjectBuilder { public class TeaVMBuilder extends IncrementalProjectBuilder {
private static final int TICKS_PER_PROFILE = 10000;
private URL[] classPath; private URL[] classPath;
private IContainer[] sourceContainers; private IContainer[] sourceContainers;
private IContainer[] classFileContainers; private IContainer[] classFileContainers;
private Set<IProject> usedProjects = new HashSet<>(); private Set<IProject> usedProjects = new HashSet<>();
private static Map<TeaVMProfile, Set<String>> profileClasses = new WeakHashMap<>();
@Override @Override
protected IProject[] build(int kind, Map<String, String> args, IProgressMonitor monitor) throws CoreException { protected IProject[] build(int kind, Map<String, String> 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(); TeaVMProjectSettings projectSettings = getProjectSettings();
projectSettings.load(); TeaVMProfile profiles[] = getEnabledProfiles(projectSettings);
TeaVMTool tool = new TeaVMTool(); monitor.beginTask("Running TeaVM", profiles.length * TICKS_PER_PROFILE);
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));
try { try {
monitor.beginTask("Running TeaVM", 10000); prepareClassPath();
tool.generate(); ClassLoader classLoader = new URLClassLoader(classPath, TeaVMBuilder.class.getClassLoader());
removeMarkers(); for (TeaVMProfile profile : profiles) {
if (tool.getDependencyViolations().hasMissingItems()) { SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, TICKS_PER_PROFILE);
putMarkers(tool.getDependencyViolations()); 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 { } finally {
monitor.done();
sourceContainers = null; sourceContainers = null;
classFileContainers = null; classFileContainers = null;
classPath = null; classPath = null;
@ -72,6 +55,56 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
return !usedProjects.isEmpty() ? usedProjects.toArray(new IProject[0]) : null; 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<String> classesToResources(Collection<String> classNames) { private Set<String> classesToResources(Collection<String> classNames) {
Set<String> resourcePaths = new HashSet<>(); Set<String> resourcePaths = new HashSet<>();
for (String className : classNames) { for (String className : classNames) {
@ -86,8 +119,8 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
return resourcePaths; return resourcePaths;
} }
private boolean shouldBuild() throws CoreException { private boolean shouldBuild(TeaVMProfile profile) throws CoreException {
Set<String> classes = TeaVMEclipsePlugin.getDefault().getProjectClasses(getProject()); Collection<String> classes = getClasses(profile);
if (classes.isEmpty()) { if (classes.isEmpty()) {
return true; return true;
} }
@ -100,7 +133,7 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
return false; return false;
} }
private boolean shouldBuild(Set<String> classes, IResourceDelta delta) { private boolean shouldBuild(Collection<String> classes, IResourceDelta delta) {
if (classes.contains(delta.getResource().getFullPath().toString())) { if (classes.contains(delta.getResource().getFullPath().toString())) {
return true; return true;
} }
@ -112,6 +145,18 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
return false; return false;
} }
private Collection<String> getClasses(TeaVMProfile profile) {
Set<String> classes;
synchronized (profileClasses) {
classes = profileClasses.get(profile);
}
return classes != null ? new HashSet<>(classes) : new HashSet<String>();
}
private void setClasses(TeaVMProfile profile, Collection<String> classes) {
profileClasses.put(profile, new HashSet<>(classes));
}
private void removeMarkers() throws CoreException { private void removeMarkers() throws CoreException {
getProject().deleteMarkers(TeaVMEclipsePlugin.DEPENDENCY_MARKER_ID, true, IResource.DEPTH_INFINITE); getProject().deleteMarkers(TeaVMEclipsePlugin.DEPENDENCY_MARKER_ID, true, IResource.DEPTH_INFINITE);
} }
@ -249,11 +294,6 @@ public class TeaVMBuilder extends IncrementalProjectBuilder {
return TeaVMEclipsePlugin.getDefault().getSettings(getProject()); return TeaVMEclipsePlugin.getDefault().getSettings(getProject());
} }
private ClassLoader prepareClassLoader() throws CoreException {
prepareClassPath();
return new URLClassLoader(classPath, TeaVMBuilder.class.getClassLoader());
}
private Set<IProject> getRelatedProjects() throws CoreException { private Set<IProject> getRelatedProjects() throws CoreException {
Set<IProject> projects = new HashSet<>(); Set<IProject> projects = new HashSet<>();
Set<IProject> visited = new HashSet<>(); Set<IProject> visited = new HashSet<>();

View File

@ -41,7 +41,6 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin {
public static final String DEPENDENCY_MARKER_ID = ID + ".dependencyMarker"; public static final String DEPENDENCY_MARKER_ID = ID + ".dependencyMarker";
private static TeaVMEclipsePlugin defaultInstance; private static TeaVMEclipsePlugin defaultInstance;
private ConcurrentMap<IProject, TeaVMProjectSettings> settingsMap = new ConcurrentHashMap<>(); private ConcurrentMap<IProject, TeaVMProjectSettings> settingsMap = new ConcurrentHashMap<>();
private Map<IProject, Set<String>> projectClasses = new WeakHashMap<>();
public TeaVMEclipsePlugin() { public TeaVMEclipsePlugin() {
defaultInstance = this; defaultInstance = this;
@ -132,18 +131,4 @@ public class TeaVMEclipsePlugin extends AbstractUIPlugin {
} }
} }
} }
public void setProjectClasses(IProject project, Set<String> classes) {
synchronized (projectClasses) {
projectClasses.put(project, new HashSet<>(classes));
}
}
public Set<String> getProjectClasses(IProject project) {
Set<String> classes;
synchronized (projectClasses) {
classes = projectClasses.get(project);
}
return classes != null ? new HashSet<>(classes) : new HashSet<String>();
}
} }

View File

@ -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);
}

View File

@ -7,13 +7,13 @@ import org.eclipse.core.runtime.CoreException;
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public interface TeaVMProjectSettings { 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; void save() throws CoreException;

View File

@ -4,13 +4,12 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.variables.VariablesPlugin; import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IType; 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.dialogs.IDialogConstants;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.swt.SWT; import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent; 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.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider; import org.eclipse.ui.model.WorkbenchLabelProvider;
import org.eclipse.ui.views.navigator.ResourceComparator; import org.eclipse.ui.views.navigator.ResourceComparator;
import org.teavm.eclipse.TeaVMEclipsePlugin; import org.teavm.eclipse.TeaVMProfile;
import org.teavm.eclipse.TeaVMProjectSettings; import org.teavm.eclipse.TeaVMProjectSettings;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class TeaVMProjectPropertyWidget extends Composite { public class TeaVMProfileDialog extends Dialog {
private Button natureButton; private Text nameField;
private Text mainClassField; private Text mainClassField;
private Button mainClassChooseButton; private Button mainClassChooseButton;
private Text targetDirectoryField; private Text targetDirectoryField;
private Button targetDirectoryWorkspaceButton; private Button targetDirectoryWorkspaceButton;
private Button targetDirectoryFileSystemButton; private Button targetDirectoryFileSystemButton;
private Text targetFileNameField;
private Button minifyingButton;
private IJavaProject javaProject; private IJavaProject javaProject;
private IRunnableContext runnableContext; private TeaVMProjectSettings settings;
private TeaVMProfile profile;
public TeaVMProjectPropertyWidget(Composite parent) { public TeaVMProfileDialog(Shell shell, TeaVMProjectSettings settings, TeaVMProfile profile) {
super(parent, SWT.NONE); super(shell);
GridLayout layout = new GridLayout(1, false); this.settings = settings;
layout.verticalSpacing = 10; this.profile = profile;
layout.marginWidth = 10; setShellStyle(getShellStyle() | SWT.RESIZE);
setLayout(layout); }
natureButton = new Button(this, SWT.CHECK);
natureButton.setText("TeaVM build enabled");
createOptionsContainer();
natureButton.addSelectionListener(new SelectionAdapter() {
@Override @Override
public void widgetSelected(SelectionEvent e) { protected void configureShell(Shell newShell) {
updateEnabled(natureButton.getSelection()); super.configureShell(newShell);
} newShell.setText("Editing TeaVM profile");
});
} }
private void updateEnabled(boolean enabled) { @Override
mainClassField.setEnabled(enabled); protected boolean isResizable() {
mainClassChooseButton.setEnabled(enabled); return true;
targetDirectoryField.setEnabled(enabled);
targetDirectoryWorkspaceButton.setEnabled(enabled);
targetDirectoryFileSystemButton.setEnabled(enabled);
} }
private void createOptionsContainer() { @Override
Composite container = new Composite(this, SWT.NONE); protected Control createDialogArea(Composite parent) {
container.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); Composite area = (Composite)super.createDialogArea(parent);
GridLayout layout = new GridLayout(); area.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, true));
layout.numColumns = 2; 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; layout.horizontalSpacing = 5;
container.setLayout(layout); container.setLayout(layout);
createNameField(container);
createMainClassField(container); createMainClassField(container);
createTargetDirectoryField(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) { private void createMainClassField(Composite container) {
@ -81,9 +90,8 @@ public class TeaVMProjectPropertyWidget extends Composite {
Composite row = new Composite(container, SWT.NONE); Composite row = new Composite(container, SWT.NONE);
row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
GridLayout rowLayout = new GridLayout(); GridLayout rowLayout = new GridLayout(2, false);
rowLayout.numColumns = 2; rowLayout.marginWidth = 2;
rowLayout.horizontalSpacing = 2;
row.setLayout(rowLayout); row.setLayout(rowLayout);
mainClassField = new Text(row, SWT.SINGLE | SWT.BORDER); mainClassField = new Text(row, SWT.SINGLE | SWT.BORDER);
@ -104,13 +112,12 @@ public class TeaVMProjectPropertyWidget extends Composite {
Composite row = new Composite(container, SWT.NONE); Composite row = new Composite(container, SWT.NONE);
row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); row.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
GridLayout rowLayout = new GridLayout(); GridLayout rowLayout = new GridLayout(3, false);
rowLayout.numColumns = 3; rowLayout.marginWidth = 2;
rowLayout.horizontalSpacing = 2;
row.setLayout(rowLayout); row.setLayout(rowLayout);
targetDirectoryField = new Text(row, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); 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 = new Button(row, SWT.PUSH);
targetDirectoryWorkspaceButton.setText("Workspace..."); 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) { private void createMinifyField(Composite container) {
this.runnableContext = runnableContext; 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() { private void chooseMainClass() {
@ -174,59 +196,38 @@ public class TeaVMProjectPropertyWidget extends Composite {
} }
} }
public void load(IProject project) { @Override
try { protected void okPressed() {
natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID)); if (save()) {
TeaVMProjectSettings settings = TeaVMEclipsePlugin.getDefault().getSettings(project); super.okPressed();
settings.load(); } else {
mainClassField.setText(settings.getMainClass()); MessageBox mbox = new MessageBox(getShell(), SWT.ICON_ERROR);
targetDirectoryField.setText(settings.getTargetDirectory()); mbox.setMessage("Name " + nameField.getText() + " already used by another profile");
updateEnabled(natureButton.getSelection()); mbox.setText("Invalid data supplied");
} catch (CoreException e) { mbox.open();
reportError(e);
} }
} }
public boolean save(IProject project) { private void load() {
try { nameField.setText(profile.getName());
if (natureButton.getSelection()) { mainClassField.setText(profile.getMainClass() != null ? profile.getMainClass() : "");
if (!project.hasNature(TeaVMEclipsePlugin.NATURE_ID)) { targetDirectoryField.setText(profile.getTargetDirectory());
addNature(project); targetFileNameField.setText(profile.getTargetFileName());
minifyingButton.setSelection(profile.isMinifying());
} }
} else {
if (project.hasNature(TeaVMEclipsePlugin.NATURE_ID)) { private boolean save() {
removeNature(project); String name = nameField.getText().trim();
} TeaVMProfile existingProfile = settings.getProfile(name);
} if (existingProfile != null && existingProfile != profile) {
TeaVMProjectSettings settings = TeaVMEclipsePlugin.getDefault().getSettings(project);
settings.setMainClass(mainClassField.getText().trim());
settings.setTargetDirectory(targetDirectoryField.getText());
settings.save();
return true;
} catch (CoreException e) {
reportError(e);
return false; return false;
} }
} profile.setName(name);
String mainClass = mainClassField.getText().trim();
private void addNature(final IProject project) { profile.setMainClass(!mainClass.isEmpty() ? mainClass : null);
reportStatus(TeaVMEclipsePlugin.getDefault().addNature(runnableContext, project)); profile.setTargetDirectory(targetDirectoryField.getText());
} profile.setTargetFileName(targetFileNameField.getText().trim());
profile.setMinifying(minifyingButton.getSelection());
private void removeNature(final IProject project) { return true;
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);
}
} }
} }

View File

@ -2,42 +2,228 @@ 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.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject; import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.JavaCore; import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Control; 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.IWorkbenchPropertyPage;
import org.eclipse.ui.PlatformUI; import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PropertyPage; import org.eclipse.ui.dialogs.PropertyPage;
import org.teavm.eclipse.TeaVMEclipsePlugin; import org.teavm.eclipse.TeaVMEclipsePlugin;
import org.teavm.eclipse.TeaVMProfile;
import org.teavm.eclipse.TeaVMProjectSettings;
/** /**
* *
* @author Alexey Andreev <konsoletyper@gmail.com> * @author Alexey Andreev <konsoletyper@gmail.com>
*/ */
public class TeaVMProjectPropertyPage extends PropertyPage implements IWorkbenchPropertyPage { 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 @Override
protected Control createContents(Composite parent) { protected Control createContents(Composite parent) {
widget = new TeaVMProjectPropertyWidget(parent); project = (IProject)getElement().getAdapter(IProject.class);
widget.setRunnableContext(PlatformUI.getWorkbench().getProgressService()); settings = TeaVMEclipsePlugin.getDefault().getSettings(project);
IProject project = (IProject)getElement().getAdapter(IProject.class);
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 { try {
if (project.hasNature(JavaCore.NATURE_ID)) { natureButton.setSelection(project.hasNature(TeaVMEclipsePlugin.NATURE_ID));
IJavaProject javaProject = JavaCore.create(project);
widget.setJavaProject(javaProject);
}
} catch (CoreException e) { } catch (CoreException e) {
TeaVMEclipsePlugin.logError(e); reportStatus(e.getStatus());
} }
widget.load(project); loadProfiles();
return widget;
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 @Override
public boolean performOk() { public boolean performOk() {
widget.save((IProject)getElement().getAdapter(IProject.class)); try {
updateNature();
settings.save();
} catch (CoreException e) {
reportStatus(e.getStatus());
}
return super.performOk(); 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);
}
}
} }

View File

@ -3,7 +3,7 @@
<description name="TeaVM update site"> <description name="TeaVM update site">
TeaVM update site TeaVM update site
</description> </description>
<feature url="features/teavm.eclipse.feature_0.2.0.201408071607.jar" id="teavm.eclipse.feature" version="0.2.0.201408071607" os="aix,hpux,linux,macosx,qnx,solaris,win32" ws="carbon,cocoa,gtk,motif,photon,win32,wpf" arch="ia64,ia64_32,PA_RISC,ppc,sparc,x86,x86_64"> <feature url="features/teavm.eclipse.feature_0.2.0.201409170959.jar" id="teavm.eclipse.feature" version="0.2.0.201409170959" os="aix,hpux,linux,macosx,qnx,solaris,win32" ws="carbon,cocoa,gtk,motif,photon,win32,wpf" arch="ia64,ia64_32,PA_RISC,ppc,sparc,x86,x86_64">
<category name="teavm"/> <category name="teavm"/>
</feature> </feature>
<category-def name="teavm" label="TeaVM"/> <category-def name="teavm" label="TeaVM"/>