From a582399219bd58df1e5704d45fbd2a28961ad948 Mon Sep 17 00:00:00 2001 From: Donat Csikos Date: Fri, 19 Apr 2024 16:27:16 +0200 Subject: [PATCH] Composite Creation Implementation Added most of the features to create a non functional workspace composite, including: - Definition of composite via wizard and working set GUI - Adding projects to the composite via wizard and properties - Changing composite properties via properties menu Import of external projects has yet to be implemented Signed-off-by: kuzniarz --- .../META-INF/MANIFEST.MF | 3 +- .../buildship/core/CompositeProperties.java | 280 ++++++++++++++++ .../BuildConfigurationPersistence.java | 8 +- .../configuration/CompositeConfiguration.java | 33 ++ .../configuration/ConfigurationManager.java | 7 +- .../DefaultCompositeConfiguration.java | 77 +++++ .../DefaultConfigurationManager.java | 61 +++- .../core/internal/i18n/CoreMessages.java | 1 + .../internal/util/binding/Validators.java | 39 +++ .../internal/workspace/BuildComposite.java | 28 ++ .../internal/i18n/CoreMessages.properties | 3 +- org.eclipse.buildship.ui/css/dark-theme.css | 2 +- .../full/etool16/new_gradlecomposite_obj.png | Bin 0 -> 810 bytes .../etool16/new_gradlecomposite_obj@2x.png | Bin 0 -> 1689 bytes .../icons/full/obj16/gradlecomposite_obj.png | Bin 0 -> 704 bytes .../full/obj16/gradlecomposite_obj@2x.png | Bin 0 -> 1265 bytes org.eclipse.buildship.ui/plugin.xml | 123 +++++++ .../composite/WorkingSetProperyTester.java | 43 +++ .../preferences/AbstractPropertiesPage.java | 125 ++++++++ ...eCompositeImportOptionsPreferencePage.java | 68 ++-- ...dleCompositeRootProjectPreferencePage.java | 109 ++++++- ...reateWorkspaceCompositePreferencePage.java | 299 ++++++++++++++++++ .../GradleDistributionValidatingListener.java | 2 +- .../GradleProjectPreferencePage.java | 2 +- ...radleWorkspaceCompositePreferencePage.java | 8 + .../preferences/ValidatingListener.java | 2 +- ...xternalProjectDialogSelectionListener.java | 114 +++++++ .../util/widget/GradleProjectGroup.java | 164 ++++++++-- .../internal/view/task/RemoveComposite.java | 57 ++++ .../AbstractCompositeWizardPage.java | 234 ++++++++++++++ .../AbstractWorkspaceCompositeWizard.java | 26 +- .../CompositeConfiguration.java | 227 +++++++++++++ .../CompositeCreationConfiguration.java | 46 +++ .../CompositeCreationWizardController.java | 71 +++++ .../CompositeImportWizardController.java | 235 ++++++++++++++ .../CompositeRootProjectConfiguration.java | 51 +++ .../CompositeRootProjectWizardController.java | 49 +++ .../ExternalGradleProject.java | 31 ++ .../ExternalGradleProjectAdapter.java | 21 ++ .../ExternalProjectAdapterFactory.java | 30 ++ ...dleCreateWorkspaceCompositeWizardPage.java | 159 +++++++++- .../GradleImportOptionsWizardPage.java | 171 +++++++++- .../GradleRootProjectWizardPage.java | 96 +++++- .../GradleWorkspaceCompositeUpdater.java | 238 ++++++++++++++ .../IGradleCompositeIDs.java | 23 ++ .../WorkspaceCompositeCreationWizard.java | 46 +-- .../WorkspaceCompositeWizardMessages.java | 5 + .../CompositePropertyChangeListener.java | 101 ++++++ .../workspace/RemoveCompositeHandler.java | 40 +++ .../ui/internal/workspace/StartupSetup.java | 26 ++ ...orkspaceCompositeWizardMessages.properties | 10 +- 51 files changed, 3457 insertions(+), 137 deletions(-) create mode 100644 org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/CompositeProperties.java create mode 100644 org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/CompositeConfiguration.java create mode 100644 org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultCompositeConfiguration.java create mode 100644 org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/BuildComposite.java create mode 100644 org.eclipse.buildship.ui/icons/full/etool16/new_gradlecomposite_obj.png create mode 100644 org.eclipse.buildship.ui/icons/full/etool16/new_gradlecomposite_obj@2x.png create mode 100644 org.eclipse.buildship.ui/icons/full/obj16/gradlecomposite_obj.png create mode 100644 org.eclipse.buildship.ui/icons/full/obj16/gradlecomposite_obj@2x.png create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/composite/WorkingSetProperyTester.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/AbstractPropertiesPage.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCreateWorkspaceCompositePreferencePage.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/file/ExternalProjectDialogSelectionListener.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/view/task/RemoveComposite.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractCompositeWizardPage.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeConfiguration.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationConfiguration.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationWizardController.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeImportWizardController.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectConfiguration.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectWizardController.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProject.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProjectAdapter.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalProjectAdapterFactory.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleWorkspaceCompositeUpdater.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/IGradleCompositeIDs.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/CompositePropertyChangeListener.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/RemoveCompositeHandler.java create mode 100644 org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/StartupSetup.java diff --git a/org.eclipse.buildship.core/META-INF/MANIFEST.MF b/org.eclipse.buildship.core/META-INF/MANIFEST.MF index 9ec540f6d6..8c7b55446e 100644 --- a/org.eclipse.buildship.core/META-INF/MANIFEST.MF +++ b/org.eclipse.buildship.core/META-INF/MANIFEST.MF @@ -19,7 +19,8 @@ Require-Bundle: org.eclipse.core.expressions, org.gradle.toolingapi;bundle-version="[8.6.0,8.7.0)";visibility:=reexport, com.google.guava;bundle-version="33.0.0", com.google.gson;bundle-version="[2.7.0,3.0.0)", - org.eclipse.buildship.compat;visibility:=reexport + org.eclipse.buildship.compat;visibility:=reexport, + org.eclipse.ui.workbench Bundle-ActivationPolicy: lazy Import-Package: org.slf4j;version="1.7.2" Export-Package: org.eclipse.buildship.core, diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/CompositeProperties.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/CompositeProperties.java new file mode 100644 index 0000000000..6ac50ac3e9 --- /dev/null +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/CompositeProperties.java @@ -0,0 +1,280 @@ +/******************************************************************************* + * Copyright (c) 2019 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ +package org.eclipse.buildship.core; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import com.google.common.base.Preconditions; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.IAdaptable; + +import org.eclipse.buildship.core.internal.configuration.CompositeConfiguration; + +public class CompositeProperties { + + private final File compositePreferencesDir; + + private final IAdaptable[] projectList; + private final Boolean overwriteWorkspaceSettings; + private final GradleDistribution distribution; + private final File gradleUserHome; + private final File javaHome; + private final Boolean buildScansEnabled; + private final Boolean offlineMode; + private final Boolean autoSync; + private final List arguments; + private final List jvmArguments; + private final Boolean showConsoleView; + private final Boolean showExecutionsView; + private final Boolean useProjectAsRoot; + private final File rootProject; + + private static final String KEY_COMPOSITE_PROJECTS = "composite.projects"; + private static final String KEY_OVERWRITE_WORKSPACE_SETTINGS = "override.workspace.settings"; + private static final String KEY_DISTRIBUTION = "connection.gradle.distribution"; + private static final String KEY_GRADLE_USER_HOME = "gradle.user.home"; + private static final String KEY_JAVA_HOME = "java.home"; + private static final String KEY_BUILD_SCANS_ENABLED = "build.scans.enabled"; + private static final String KEY_OFFLINE_MODE = "offline.mode"; + private static final String KEY_AUTO_SYNC = "auto.sync"; + private static final String KEY_ARGUMENTS = "arguments"; + private static final String KEY_JVM_ARGUMENTS = "jvm.arguments"; + private static final String KEY_SHOW_CONSOLE_VIEW = "show.console.view"; + private static final String KEY_SHOW_EXECUTION_VIEW = "show.executions.view"; + private static final String KEY_USE_PROJECT_AS_ROOT = "project.as.root"; + private static final String KEY_ROOT_PROJECT = "root.project"; + + private CompositeProperties(CompositePropertiesBuilder builder) { + this.compositePreferencesDir = Preconditions.checkNotNull(builder.compositeDirectory); + this.projectList = builder.projectList; + this.overwriteWorkspaceSettings = builder.overrideWorkspaceConfiguration; + this.distribution = builder.gradleDistribution == null ? GradleDistribution.fromBuild() : builder.gradleDistribution; + this.gradleUserHome = builder.gradleUserHome == null ? null: builder.gradleUserHome; + this.javaHome = builder.javaHome == null ? null : builder.javaHome; + this.buildScansEnabled = builder.buildScansEnabled; + this.offlineMode = builder.offlineMode; + this.autoSync = builder.autoSync; + this.arguments = builder.arguments == null ? Collections.emptyList() : builder.arguments; + this.jvmArguments = builder.jvmArguments == null ? Collections.emptyList() : builder.jvmArguments; + this.showConsoleView = builder.showConsoleView; + this.showExecutionsView = builder.showExecutionsView; + this.useProjectAsRoot = builder.projectAsCompositeRoot; + this.rootProject = builder.rootProject == null ? null: builder.rootProject; + + + } + + public static CompositePropertiesReader getCompositeReaderForFile(File compositeProperties) { + return new CompositePropertiesReader(compositeProperties); + } + + public static CompositePropertiesBuilder forRootProjectDirectory(File rootProjectDirectory) { + return new CompositePropertiesBuilder(rootProjectDirectory); + } + + public static CompositePropertiesBuilder forCompositeConfiguration(CompositeConfiguration compositeConf) { + return new CompositePropertiesBuilder(compositeConf); + } + + public Properties toProperties() { + Properties prop = new Properties(); + + prop.put(KEY_COMPOSITE_PROJECTS, getProjectString(this.projectList)); + prop.put(KEY_OVERWRITE_WORKSPACE_SETTINGS, this.overwriteWorkspaceSettings.toString()); + prop.put(KEY_DISTRIBUTION, this.distribution == null ? GradleDistribution.fromBuild() : this.distribution.toString()); + prop.put(KEY_GRADLE_USER_HOME, this.gradleUserHome == null ? "" : this.gradleUserHome.getAbsolutePath()); + prop.put(KEY_JAVA_HOME, this.javaHome == null ? "" : this.javaHome.getAbsolutePath()); + prop.put(KEY_BUILD_SCANS_ENABLED, this.buildScansEnabled.toString()); + prop.put(KEY_OFFLINE_MODE, this.offlineMode.toString()); + prop.put(KEY_AUTO_SYNC, this.autoSync.toString()); + prop.put(KEY_ARGUMENTS, removeBrackets(this.arguments.toString())); + prop.put(KEY_JVM_ARGUMENTS, removeBrackets(this.jvmArguments.toString())); + prop.put(KEY_SHOW_CONSOLE_VIEW, this.showConsoleView.toString()); + prop.put(KEY_SHOW_EXECUTION_VIEW, this.showExecutionsView.toString()); + prop.put(KEY_USE_PROJECT_AS_ROOT, this.useProjectAsRoot.toString()); + prop.put(KEY_ROOT_PROJECT, this.rootProject == null ? "" : this.rootProject.toString()); + return prop; + } + + private String getProjectString(IAdaptable[] projects) { + StringBuilder sb = new StringBuilder(); + for (Iterator it = Arrays.asList(projects).iterator(); it.hasNext();) { + IAdaptable project = it.next(); + if (project instanceof IProject) { + if (it.hasNext()) { + sb.append(((IProject) project).getName() + ", "); + } else { + sb.append(((IProject) project).getName()); + } + } else if (project instanceof IResource) { + IResource externalProject = (IResource) project; + System.out.println(externalProject.getName()); + } + } + return sb.toString(); + } + + private String removeBrackets(String arguments) { + return arguments.replace("[", "").replace("]", "").replace(",", ""); + } + + public static final class CompositePropertiesBuilder { + + private final File compositeDirectory; + public IAdaptable[] projectList; + private boolean overrideWorkspaceConfiguration = false; + private GradleDistribution gradleDistribution; + private File gradleUserHome = null; + private File javaHome = null; + private boolean buildScansEnabled = false; + private boolean offlineMode = false; + private boolean autoSync = false; + private List arguments = new ArrayList<>(); + private List jvmArguments = new ArrayList<>(); + private boolean showConsoleView = true; + private boolean showExecutionsView = true; + private boolean projectAsCompositeRoot = false; + private File rootProject = null; + + private CompositePropertiesBuilder(File compositeDirectory) { + this.compositeDirectory = compositeDirectory; + } + + public CompositePropertiesBuilder(CompositeConfiguration compositeConf) { + this.compositeDirectory = compositeConf.getCompositeDir(); + this.projectList = compositeConf.getProjectList(); + this.overrideWorkspaceConfiguration = compositeConf.getBuildConfiguration().isOverrideWorkspaceSettings(); + this.gradleDistribution = compositeConf.getBuildConfiguration().getGradleDistribution(); + this.gradleUserHome = compositeConf.getBuildConfiguration().getGradleUserHome(); + this.javaHome = compositeConf.getBuildConfiguration().getJavaHome(); + this.buildScansEnabled = compositeConf.getBuildConfiguration().isBuildScansEnabled(); + this.offlineMode = compositeConf.getBuildConfiguration().isOfflineMode(); + this.autoSync = compositeConf.getBuildConfiguration().isAutoSync(); + this.arguments = compositeConf.getBuildConfiguration().getArguments(); + this.jvmArguments = compositeConf.getBuildConfiguration().getJvmArguments(); + this.showConsoleView = compositeConf.getBuildConfiguration().isShowConsoleView(); + this.showExecutionsView = compositeConf.getBuildConfiguration().isShowExecutionsView(); + this.projectAsCompositeRoot = compositeConf.projectAsCompositeRoot(); + this.rootProject = compositeConf.getRootProject(); + + } + + public CompositePropertiesBuilder projectList(IAdaptable[] projectList) { + this.projectList = projectList; + return this; + } + + public CompositePropertiesBuilder overrideWorkspaceConfiguration(boolean overrideWorkspaceConfiguration) { + this.overrideWorkspaceConfiguration = overrideWorkspaceConfiguration; + return this; + } + + public CompositePropertiesBuilder gradleDistribution(GradleDistribution gradleDistribution) { + this.gradleDistribution = gradleDistribution; + return this; + } + + public CompositePropertiesBuilder gradleUserHome(File gradleUserHome) { + this.gradleUserHome = gradleUserHome; + return this; + } + + public CompositePropertiesBuilder javaHome(File javaHome) { + this.javaHome = javaHome; + return this; + } + + public CompositePropertiesBuilder buildScansEnabled(boolean buildScansEnabled) { + this.buildScansEnabled = buildScansEnabled; + return this; + } + + public CompositePropertiesBuilder offlineMode(boolean offlineMode) { + this.offlineMode = offlineMode; + return this; + } + + public CompositePropertiesBuilder autoSync(boolean autoSync) { + this.autoSync = autoSync; + return this; + } + + public CompositePropertiesBuilder arguments(List arguments) { + this.arguments = arguments; + return this; + } + + public CompositePropertiesBuilder jvmArguments(List jvmArguments) { + this.jvmArguments = jvmArguments; + return this; + } + + public CompositePropertiesBuilder showConsoleView(boolean showConsoleView) { + this.showConsoleView = showConsoleView; + return this; + } + + public CompositePropertiesBuilder showExecutionsView(boolean showExecutionsView) { + this.showExecutionsView = showExecutionsView; + return this; + } + + public CompositePropertiesBuilder projectAsCompositeRoot(boolean projectAsCompositeRoot) { + this.projectAsCompositeRoot = projectAsCompositeRoot; + return this; + } + + public CompositePropertiesBuilder rootProject(File rootProject) { + this.rootProject = rootProject; + return this; + } + + public CompositeProperties build() { + return new CompositeProperties(this); + } + } + + public static final class CompositePropertiesReader { + private final File compositeDirectory; + private Properties compositeProperties = new Properties(); + + private CompositePropertiesReader(File compositeDirectory) { + this.compositeDirectory = compositeDirectory; + try { + FileInputStream input= new FileInputStream(this.compositeDirectory); + this.compositeProperties = new Properties(); + this.compositeProperties.load(input); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public boolean getProjectAsCompositeRoot() { + return Boolean.valueOf(this.compositeProperties.get(KEY_USE_PROJECT_AS_ROOT).toString()); + } + + public File getRootProject() { + return new File(this.compositeProperties.get(KEY_ROOT_PROJECT).toString()); + } + + //If needed implement reader for other properties + + } +} diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/BuildConfigurationPersistence.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/BuildConfigurationPersistence.java index 5bbdcc6d22..3e408f8d7b 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/BuildConfigurationPersistence.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/BuildConfigurationPersistence.java @@ -58,7 +58,13 @@ public BuildConfigurationProperties readBuildConfiguratonProperties(File project return readPreferences(preferences, projectDir); } - public void saveBuildConfiguration(IProject project, BuildConfigurationProperties properties) { + public DefaultBuildConfigurationProperties readCompositeBuildProperties(File compositeDir) { + Preconditions.checkNotNull(compositeDir); + PreferenceStore preferences = PreferenceStore.forPreferenceFile(compositeDir); + return readPreferences(preferences, compositeDir); + } + + public void saveBuildConfiguration(IProject project, DefaultBuildConfigurationProperties properties) { Preconditions.checkNotNull(project); Preconditions.checkNotNull(properties); PreferenceStore preferences = PreferenceStore.forProjectScope(project, PREF_NODE); diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/CompositeConfiguration.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/CompositeConfiguration.java new file mode 100644 index 0000000000..3d9c50961d --- /dev/null +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/CompositeConfiguration.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2019 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.core.internal.configuration; + +import java.io.File; + +import org.eclipse.core.runtime.IAdaptable; + +/** + * Configuration for a workspace composite in a Gradle build. + * + * @author Sebastian Kuzniarz + */ +public interface CompositeConfiguration { + + File getCompositeDir(); + + IAdaptable[] getProjectList(); + + BuildConfiguration getBuildConfiguration(); + + Boolean projectAsCompositeRoot(); + + File getRootProject(); +} diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/ConfigurationManager.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/ConfigurationManager.java index 436eece597..7a3e0c7aec 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/ConfigurationManager.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/ConfigurationManager.java @@ -14,6 +14,7 @@ import org.eclipse.core.resources.IProject; import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.ui.IWorkingSet; import org.eclipse.buildship.core.GradleDistribution; @@ -49,7 +50,11 @@ BuildConfiguration createBuildConfiguration(File rootProjectDirectory, boolean o void deleteProjectConfiguration(IProject project); - RunConfiguration loadRunConfiguration(ILaunchConfiguration configuration); + CompositeConfiguration loadCompositeConfiguration(IWorkingSet workingSet); + + void saveCompositeConfiguration(CompositeConfiguration compConf); + + RunConfiguration loadRunConfiguration(ILaunchConfiguration launchConfiguration); TestRunConfiguration loadTestRunConfiguration(ILaunchConfiguration configuration); diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultCompositeConfiguration.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultCompositeConfiguration.java new file mode 100644 index 0000000000..867571fb4c --- /dev/null +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultCompositeConfiguration.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2019 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.core.internal.configuration; + +import java.io.File; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; + +import org.eclipse.core.runtime.IAdaptable; + +public class DefaultCompositeConfiguration implements CompositeConfiguration { + + private final File compositeDir; + private final IAdaptable[] projectList; + private final BuildConfiguration buildConfiguration; + private final Boolean projectAsCompositeRoot; + private final File rootProject; + + public DefaultCompositeConfiguration(File compositeDir, IAdaptable[] projectList, BuildConfiguration buildConfiguration, Boolean projectAsCompositeRoot, File rootProject) { + this.compositeDir = Preconditions.checkNotNull(compositeDir); + this.projectList = Preconditions.checkNotNull(projectList); + this.buildConfiguration = Preconditions.checkNotNull(buildConfiguration); + this.projectAsCompositeRoot = Preconditions.checkNotNull(projectAsCompositeRoot); + this.rootProject = Preconditions.checkNotNull(rootProject); + } + + @Override + public File getCompositeDir() { + return this.compositeDir; + } + + @Override + public IAdaptable[] getProjectList() { + return this.projectList; + } + + @Override + public BuildConfiguration getBuildConfiguration() { + return this.buildConfiguration; + } + + @Override + public File getRootProject() { + return this.rootProject; + } + + @Override + public Boolean projectAsCompositeRoot() { + return this.projectAsCompositeRoot; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof DefaultCompositeConfiguration) { + DefaultCompositeConfiguration other = (DefaultCompositeConfiguration) obj; + return Objects.equal(this.compositeDir, other.compositeDir) + && Objects.equal(this.buildConfiguration, other.buildConfiguration); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(this.compositeDir, + this.buildConfiguration); + } + +} diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultConfigurationManager.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultConfigurationManager.java index 3f963745b2..edd2e226a3 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultConfigurationManager.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/configuration/DefaultConfigurationManager.java @@ -10,18 +10,15 @@ package org.eclipse.buildship.core.internal.configuration; import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; import java.io.IOException; import java.util.Collections; import java.util.List; +import java.util.Properties; -import com.google.common.base.Optional; -import com.google.common.base.Preconditions; - -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.IPath; -import org.eclipse.core.runtime.Path; -import org.eclipse.debug.core.ILaunchConfiguration; - +import org.eclipse.buildship.core.CompositeProperties; +import org.eclipse.buildship.core.CompositeProperties.CompositePropertiesReader; import org.eclipse.buildship.core.GradleDistribution; import org.eclipse.buildship.core.internal.CorePlugin; import org.eclipse.buildship.core.internal.CoreTraceScopes; @@ -30,6 +27,15 @@ import org.eclipse.buildship.core.internal.launch.GradleRunConfigurationAttributes; import org.eclipse.buildship.core.internal.launch.GradleTestRunConfigurationAttributes; import org.eclipse.buildship.core.internal.util.file.RelativePathUtils; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.debug.core.ILaunchConfiguration; +import org.eclipse.ui.IWorkingSet; + +import com.google.common.base.Optional; +import com.google.common.base.Preconditions; /** * Default implementation for {@link ConfigurationManager}. @@ -70,6 +76,7 @@ public BuildConfiguration createBuildConfiguration(File rootProjectDirectory, bo @Override public BuildConfiguration loadBuildConfiguration(File rootDir) { + System.out.println(rootDir); Preconditions.checkNotNull(rootDir); Preconditions.checkArgument(rootDir.exists()); Optional projectCandidate = CorePlugin.workspaceOperations().findProjectByLocation(rootDir); @@ -91,6 +98,11 @@ public BuildConfiguration loadBuildConfiguration(File rootDir) { return new DefaultBuildConfiguration(buildConfigProperties, loadWorkspaceConfiguration()); } + public BuildConfiguration loadBuildConfigurationForComposite(File fileDir) { + DefaultBuildConfigurationProperties buildConfigProperties = this.buildConfigurationPersistence.readCompositeBuildProperties(fileDir); + return new DefaultBuildConfiguration(buildConfigProperties, loadWorkspaceConfiguration()); + } + @Override public void saveBuildConfiguration(BuildConfiguration configuration) { Preconditions.checkArgument(configuration instanceof DefaultBuildConfiguration, "Unknow configuration type: ", configuration.getClass()); @@ -182,6 +194,38 @@ public void deleteProjectConfiguration(IProject project) { } } + @Override + public CompositeConfiguration loadCompositeConfiguration(IWorkingSet workingSet) { + File compositePropertiesFile = CorePlugin.getInstance().getStateLocation().append("workspace-composites").append(workingSet.getName()).toFile(); + BuildConfiguration buildConfig = loadBuildConfigurationForComposite(compositePropertiesFile); + IAdaptable[] projectList = loadCompositeProjects(workingSet); + CompositePropertiesReader compositeReader = CompositeProperties.getCompositeReaderForFile(compositePropertiesFile); + boolean projectAsCompositeRoot = compositeReader.getProjectAsCompositeRoot(); + File rootProject = compositeReader.getRootProject(); + return new DefaultCompositeConfiguration(canonicalize(compositePropertiesFile), projectList, buildConfig, projectAsCompositeRoot, rootProject); + } + + private IAdaptable[] loadCompositeProjects(IWorkingSet workingSet) { + IAdaptable[] projects = workingSet.getElements(); + //TODO (kuzniarz) implement load mechanism that reads external gradle projects from properties file. Needs a save mechanism first... + return projects; + } + + @Override + public void saveCompositeConfiguration(CompositeConfiguration compConf) { + try { + FileOutputStream out = new FileOutputStream(compConf.getCompositeDir()); + Properties prop = CompositeProperties.forCompositeConfiguration(compConf).build().toProperties(); + prop.store(out, ""); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + @Override public RunConfiguration loadRunConfiguration(ILaunchConfiguration launchConfiguration) { GradleRunConfigurationAttributes attributes = GradleRunConfigurationAttributes.from(launchConfiguration); @@ -305,4 +349,5 @@ private static String projectRootToRelativePath(File projectDir, File rootDir) { IPath projectPath = new Path(projectDir.getPath()); return RelativePathUtils.getRelativePath(projectPath, rootProjectPath).toPortableString(); } + } diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/i18n/CoreMessages.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/i18n/CoreMessages.java index 74d4af2a00..8df3510b1e 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/i18n/CoreMessages.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/i18n/CoreMessages.java @@ -74,6 +74,7 @@ public final class CoreMessages extends NLS { public static String Preference_Label_AutoSyncHover; public static String Preference_Label_ShowConsoleViewHover; public static String Preference_Label_ShowExecutionsViewHover; + public static String Preference_Label_Root_Project; public static String Preference_Label_ModulePath; public static String Preference_Label_ModulePathHover; diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/binding/Validators.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/binding/Validators.java index ec3ab157d5..949808362e 100644 --- a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/binding/Validators.java +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/util/binding/Validators.java @@ -20,7 +20,11 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.osgi.util.NLS; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; +import org.eclipse.buildship.core.internal.CorePlugin; import org.eclipse.buildship.core.internal.i18n.CoreMessages; /** @@ -139,6 +143,41 @@ public boolean apply(IProject project) { }; } + public static Validator uniqueWorkspaceCompositeNameValidator(final String prefix) { + return new Validator() { + + @Override + public Optional validate(String compositeName) { + if (Strings.isNullOrEmpty(compositeName)) { + return Optional.of(NLS.bind(CoreMessages.ErrorMessage_0_MustBeSpecified, prefix)); + } else if (compositeName.equals(compositeName.trim()) == false) { + return Optional.of(NLS.bind(CoreMessages.ErrorMessage_0_IsNotValid, prefix)); + } else if (compositePropertiesFileDoesNotExist(compositeName) && compositeNameAlreadyExistsinWorkspace(compositeName)){ + return Optional.of(NLS.bind(CoreMessages.ErrorMessage_0_AlreadyExists, prefix)); + } else { + return Optional.absent(); + } + } + + private boolean compositePropertiesFileDoesNotExist(String compositeName) { + return CorePlugin.getInstance().getStateLocation() + .append("workspace-composites").append(compositeName).toFile().exists(); + } + + private boolean compositeNameAlreadyExistsinWorkspace(String compositeName) { + + IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager(); + IWorkingSet[] workingSets = workingSetManager.getAllWorkingSets(); + for (IWorkingSet workingSet : workingSets) { + if (workingSet.getName().equals(compositeName)) { + return true; + } + } + return false; + } + }; + } + public static Validator validateIfConditionFalse(final Validator validator, final Property condition) { return new Validator() { @Override diff --git a/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/BuildComposite.java b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/BuildComposite.java new file mode 100644 index 0000000000..a6a5b59099 --- /dev/null +++ b/org.eclipse.buildship.core/src/main/java/org/eclipse/buildship/core/internal/workspace/BuildComposite.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2019 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.core.internal.workspace; + +import java.io.File; + +import org.eclipse.buildship.core.internal.CorePlugin; + +public class BuildComposite { + + public static File preferencesFile(String projectName) { + File preferencesFile = CorePlugin.getInstance().getStateLocation().append("workspace-composites").append(projectName).toFile(); + if (preferencesFile.canWrite()) { + return preferencesFile; + } else { + preferencesFile.getParentFile().mkdir(); + return preferencesFile; + } + } +} diff --git a/org.eclipse.buildship.core/src/main/resources/org/eclipse/buildship/core/internal/i18n/CoreMessages.properties b/org.eclipse.buildship.core/src/main/resources/org/eclipse/buildship/core/internal/i18n/CoreMessages.properties index 550c93b614..ef284b9c30 100644 --- a/org.eclipse.buildship.core/src/main/resources/org/eclipse/buildship/core/internal/i18n/CoreMessages.properties +++ b/org.eclipse.buildship.core/src/main/resources/org/eclipse/buildship/core/internal/i18n/CoreMessages.properties @@ -66,4 +66,5 @@ Preference_Label_ShowExecutionsViewHover=Makes the Executions view visible durin Preference_Label_ModulePath=Enable module support Preference_Label_ModulePathHover=Add module dependencies to the modulepath Preference_Label_ProblemsApiSupport=Enable Problems API support -Preference_Label_ProblemsApiSupportHover=Problems reported via the Problems API will appear as error markers on the UI. \ No newline at end of file +Preference_Label_ProblemsApiSupportHover=Problems reported via the Problems API will appear as error markers on the UI. +Preference_Label_Root_Project=Select specific project as composite root diff --git a/org.eclipse.buildship.ui/css/dark-theme.css b/org.eclipse.buildship.ui/css/dark-theme.css index 3d38c86297..132cb94418 100644 --- a/org.eclipse.buildship.ui/css/dark-theme.css +++ b/org.eclipse.buildship.ui/css/dark-theme.css @@ -1,4 +1,4 @@ -GradleProjectSettingsComposite, GradleDistributionGroup, AdvancedOptionsGroup { +GradleProjectSettingsComposite, GradleDistributionGroup, GradleUserHomeGroup { background-color:#515658; color:#eeeeee; } diff --git a/org.eclipse.buildship.ui/icons/full/etool16/new_gradlecomposite_obj.png b/org.eclipse.buildship.ui/icons/full/etool16/new_gradlecomposite_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..1b99f8deacee62fbdd3eaa5730b5027946819d6b GIT binary patch literal 810 zcmV+_1J(SAP)N2bPDNB8 zb~7$DE;u(kfL#Cp0;fqtK~y+Tg^*oHQ*ju^mtI6(L=@!AyRO6}osyZN_JNLWy67S* zLCFi1>cXL=q*IZ!rb0+6R)QbH(3!I|G)%mZX{Dt(6hD@8n@gvg?#!=qwzKW&e-6it zT=c+?_x#`Yd7tw?NA$MK%sF*g@NZj;C_6H^woxwRUdl5X&ijC1)##3DH98l+j-J8S0e zlS;YRZC#lG2hD8r)oPhROQD$I16Y=wKX*HwJ)S6~0%9)FT!6nM4u+r0OQtU!%^zy6 zy5Cet&{7%##xcuRl_Gq%r691I5Ab+A+X3eD>gM_H#sxg>D=B}{QOJ` zyWtxK8*h;}2El0^KyzU*I!aD6!-@-+`2h0$wiT;w*~PLBmUUC)ytB4$w>ZpGZrfBd zD7^|>+Q-ne-b80*DEexpu#DG3^EAQ22atatVcnj14#veMjC9o&Pj{41ldtocQu!Td-K==Et(Iwb~6W2}6@pZZjFB}G#ngLUl_IJ9M;#)>i5b_b)?Nf>=D zh3#u4n58yQ({<=8iar=HR2J>A&9}i}?82srU{u4dSHod?56bWk8butKA9b)#DA1iB zbueI{I10>a9}jKm{r$WLH#ZN+pzF?nIxlKQSld_cBMBID`#<64?Xrjol`MRy@$MP1 zu(q$a56*(ozw!ya@Dkiyu=MBco%vDn)_bAw$^B4|`e9^> oVEw-uvqBCL{J1K#d`Kkv1-k4L$r;waEC2ui07*qoM6N<$f-L}XCjbBd literal 0 HcmV?d00001 diff --git a/org.eclipse.buildship.ui/icons/full/etool16/new_gradlecomposite_obj@2x.png b/org.eclipse.buildship.ui/icons/full/etool16/new_gradlecomposite_obj@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2f8d2fedca476f6f3260005395c9428ec5bbd2eb GIT binary patch literal 1689 zcmV;K24?w*P)N2bPDNB8 zb~7$DE;u(kfL#Cp1{O&~K~z{r&6EjHQ%4-e#i?W48O7QbP^n{Er&2*Y0nv(B>w!9q zV|7}kb*6{Yiqt9|C346us8t*U5fKO=S~Oa+R2wJEYp)YL+okUI2-dV0+&>orpL#MPd z;BvTa9WqiS9x{U%&xyb&RfL%Rroi}DmMB{>Zj>Yg0s0iNbJX|rmq>Qn5`xeG8 za)LJY#M@1jmXp^#>62Bo2P#=h)seJt+nOZ5sRP*j3^I?}GeH+1dao&* z-8V@S!q1#eFY~Teu8X?(iUUd%Kz? zSrJR|X;(H>U4@p$Qjj(jgH&7$3@ax{8%m%V(IP2@R!JG&2?f{3B9mGZ^Ch^LTCMI! z2I?IFVRznea8{TuUEPC>)kA||cm+c8QBGgxEpk$Q;~P|By~*wIP-6`KNs#c_kk{Wy_Wb?yipRKUZsHcmN!$kf_%A_# zV7o;GLBdwj7bI?l{0rN)0qUqd2~dwK&fW6$Ftedda9jy(9i8L`bT!qSDGXU#RFxG3 z*|8fT#eX^^9exkuIOcHnfEln)D+st9`->TH{VX+ed@btHO<7ItNdN{HoVet(5l!{k zb1Y&2&qb;fcst(aa~z=L^meGrI|J9FR+G0&IP@;WphKtZxJ`)mG==k=chGethfu`z zo3bInf5td!PXdrXme=i;!`n`4;F91bW4>Y?OkTDIBrUCdRrTVY57vE70wnYJ3OrZD z59<|%If5j2H^?4@LXS8D+Ujy3H(@gg5syMB+j)dIFO7LB+5thJ4HO33-OoR=cm}m6 z0orlVQ>kgHYlTAchSv&<2d)xV8O&s0h#^wdC$iEfvDZGq=@b#c*`VH8Y^cS?}0Ml}1 z@G}J8dp?0$85TaN!Vr52J~UO_&Cnx?0J%5<81V_{7as?CbtuTn{6Q+%4;4|a+QX&e zev}KyDo+60bYT$Jyyg+8jbUlcF(U;~)Es$f0L;C}HNZ;F58~>+4Pq zB5kh?f!Y|>&BF@;!?yE{Lbv`Ax(Rw*`q`R5Z44{hX8~Z?)-0pYuFnZwt|L3d2~s^~ zV^q|}ux=ch4;Z!?T`wchu1|LVcm%9GsEuLq&{e^(kCTi-yFTGZD`$O@-Dl6F7B5%U z0b9VZjpvL)yPlRCy)yRA0SqfTZ4}z|wA|=*d5;ZX*xKVppIF~B zIK${E_XGA}$cQjC!DKClmK(h;?3!JKfPaaUmK(iNewt~Sv~$*#q@7k019Tw3AnsOw jB)D78qvigu8Z+i^TdqJN34V>F00000NkvXXu0mjf6E*W; literal 0 HcmV?d00001 diff --git a/org.eclipse.buildship.ui/icons/full/obj16/gradlecomposite_obj.png b/org.eclipse.buildship.ui/icons/full/obj16/gradlecomposite_obj.png new file mode 100644 index 0000000000000000000000000000000000000000..23bd3f8917122418c2aa903531705c3a75573b02 GIT binary patch literal 704 zcmV;x0zdtUP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+=ZO9Vz&>IZ@d|N|@Oo!Ra5wP`@hb8Cd>|OM zJ6*wCE@u)VJ41pWy#Ann$YS;RLd%P!1X{xYO&(bxQW_F!qf_aqRNWjXtC44SRoCJ` z{VAy0G;18keHCJ*VOe(J$oXb=Z=H%Rmz`M87nF(R2>e)Cj(R>muo+Ls?03%wKle5q z6jrvv^L(cK=y6n?Yvkokt?AmvmfsDnnvIQ2+;7((L)@iD+I1V0?Iyl-OEXgjMa*GP zMjQr3U7>({KlL+4tz=m?$+8?x&TGF`6Om-t%~9^BNcvwQMNBT55ciId^B7|8C$Q<2 zkwO9a2V$1v6?vH~t8`fI>pU;I=-KD(xtWJepk{}_MBZ$X_C3R=Zdt5Q@HbP&lWJS9 z46Cj?NVr-#}^On7uGfzyLK4N(xZ~*=R&kNCQT(6ud%4>bNw)BD|sPWoL3!^&f!ZH mDC*@3-h91AEkyqpBGDh9InnO(a^_qB0000M=^8& literal 0 HcmV?d00001 diff --git a/org.eclipse.buildship.ui/icons/full/obj16/gradlecomposite_obj@2x.png b/org.eclipse.buildship.ui/icons/full/obj16/gradlecomposite_obj@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..2fc15e6361070d3469cdac5d18587f750db384ff GIT binary patch literal 1265 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02y>eSaefwW^{L9 za%BKeVQFr3E>1;MAa*k@H7+{;R{o)5N zOI86lHlSQ|jEM?NLkwz6hMMSHA|1}n%>{N*?ze4RGDqUvG6Z%Loil)?FfN61QAC8X zxk0rVmtkR*(bAp+tb2Ulv-flqIIte{o4@2odwS0Qd0tN6Q@6VTKp4?L6zL)cveW+^ zq{N-LjA$le+-9@#6B9grPY;O-cIm$Z34EHEPrOLHMWpo8KUR+8yrX0AWMnkdO)Xa8 z3{c2M7Y_+j5-mdP9mGXA=FAfq!Z*?tA)HJtp%9!`D)Gq}02ZSPY zlM34Q4tl!ze9(w*Ic7#b5u{cOj!RZm482sX#rPJNEKkp{Jme5hTC#YVXpv0WUD_dCn z!jLfGhvi=Xb$BEs9H%SKbC0dxfQQ$H!!USlysJlVerm((!UBrR)HZr;uR7DB%M5~{ zdMiww=@{)yg}E~smfsRFqT7uD%??~DeiscX{%A~7&a|yABk;~0B6&s{nt!r%s=Prb z{Djh`l;6UQlDqa2B?qN^m39;6;b4z!^2U?Ys}1>pZGyDO{qtr283w+YyC#GRD6vqM@=j=yvd zQXTcEOOHFkS(P+&r|Qy_2D)jwzJ3Gd-aJ_KdEoRp znA9JDtvdsz)Q$qh@WiUk*pY)R6}_RwIoz)gM&rFxknY%`VBAbiyo^*OUD*&9ggK3bGn$>XQ6G<*$=TMUtf|GHc)G1aY z&5yfRgUSz($4iFde6i}8IaI{48fnVNqeA7c7RgeaKmMU2bh^bV&*iLQe$IWm5>)=r zuVg9CvpCoJZpX8r^1WZkQk-XTuJg?{Z&3Nm2V^PEvpCl|wbct$Q%gMlZcUh_x&1Tn z7t`jH>rNGBsVvTQPHgdPBw~^FvpCl&`Dpp$MX@WsFN#$dBpe|^QkCNO<0>y77WY3A bxVilUY!)8Pd3MQ-00000NkvXXu0mjf@ugH{ literal 0 HcmV?d00001 diff --git a/org.eclipse.buildship.ui/plugin.xml b/org.eclipse.buildship.ui/plugin.xml index fd1fc3cdb0..4c85c89242 100644 --- a/org.eclipse.buildship.ui/plugin.xml +++ b/org.eclipse.buildship.ui/plugin.xml @@ -26,6 +26,22 @@ + + + Create a new Gradle workspace composite. + + + + @@ -127,6 +143,12 @@ id="org.eclipse.buildship.ui.views" name="Gradle"> + + @@ -423,6 +445,10 @@ type="org.eclipse.ui.views.properties.IPropertySource"> + + @@ -446,6 +472,12 @@ + + + @@ -632,6 +689,39 @@ + + + + + + + + + + + + + + + + + + @@ -644,6 +734,17 @@ + + + + + @@ -697,4 +798,26 @@ + + + + + + + + + + + + diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/composite/WorkingSetProperyTester.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/composite/WorkingSetProperyTester.java new file mode 100644 index 0000000000..f05b3b6d40 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/composite/WorkingSetProperyTester.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.composite; + +import org.eclipse.ui.IWorkingSet; +import org.eclipse.buildship.core.internal.GradlePluginsRuntimeException; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.IGradleCompositeIDs; + +/** + * Property tester to determine if the test launch shortcut should be visible in the context menus. + */ +public final class WorkingSetProperyTester extends org.eclipse.core.expressions.PropertyTester { + + private static final String PROPERTY_NAME_IS_GRADLE_COMPOSITE_ID = "gradlecomposite"; + private static final String GRADLE_COMPOSITE_ID = IGradleCompositeIDs.NATURE; + + @Override + public boolean test(Object receiver, String propertyString, Object[] args, Object expectedValue) { + if (propertyString.equals(PROPERTY_NAME_IS_GRADLE_COMPOSITE_ID)) { + return receiver instanceof IWorkingSet && isGradleComposite((IWorkingSet)receiver); + } else { + throw new GradlePluginsRuntimeException("Unrecognized property to test: " + propertyString); + } + } + + private boolean isGradleComposite(IWorkingSet workingSet) { + try { + return workingSet.getId().equals(GRADLE_COMPOSITE_ID); + } catch (Exception e) { + return false; + } + } + +} + diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/AbstractPropertiesPage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/AbstractPropertiesPage.java new file mode 100644 index 0000000000..ec8b3227a9 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/AbstractPropertiesPage.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.preferences; + +import java.util.List; + +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.ui.internal.wizard.HelpContextIdProvider; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.CompositeConfiguration; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.GradleCreateWorkspaceCompositeWizardPage; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeCreationWizard; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.PlatformUI; + +/** + * Common base class for all pages in the {@link WorkspaceCompositeCreationWizard}. + */ +public abstract class AbstractPropertiesPage extends WizardPage { + + private final CompositeConfiguration configuration; + + /** + * Constructor setting up the main messages and the validation facility for this wizard page. + * + * @param name the name of the page + * @param title the page title + * @param defaultMessage the default message to show when there is no validation error + * @param configuration the data model of the wizard + * @param observedProperties the subset of the properties from the data model that are managed + * on this page + */ + protected AbstractPropertiesPage(String name, String title, String defaultMessage, CompositeConfiguration configuration, final List> observedProperties) { + super(name); + + this.configuration = configuration; + + // set the basic message and the attached image + setTitle(title); + setDescription(defaultMessage); + setImageDescriptor(ImageDescriptor.createFromFile(GradleCreateWorkspaceCompositeWizardPage.class, "/icons/full/wizban/wizard.png")); //$NON-NLS-1$ + } + + protected CompositeConfiguration getConfiguration() { + return this.configuration; + } + + @Override + public void createControl(Composite parent) { + // align dialog units to the current resolution + initializeDialogUnits(parent); + + // create the container control + Composite pageControl = createWizardPageContent(parent); + + // assign the created control to the wizard page + setControl(pageControl); + } + + private Composite createWizardPageContent(Composite parent) { + // create a scrollable root to handle resizing + ScrolledComposite externalRoot = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL); + externalRoot.setExpandHorizontal(true); + externalRoot.setExpandVertical(true); + externalRoot.setMinSize(new Point(230, 380)); + + // add the controls inside the root composite + Composite container = new Composite(externalRoot, SWT.NONE); + createWidgets(container); + + // also compute the size of the container, otherwise the ScrolledComposite's content is not + // rendered properly + Point containerSize = container.computeSize(SWT.DEFAULT, SWT.DEFAULT); + container.setSize(containerSize); + + // set the root's content and return it + externalRoot.setContent(container); + return externalRoot; + } + + /** + * Populates the widgets in the wizard page. + */ + protected abstract void createWidgets(Composite root); + + /** + * Returns text to display under the widgets. If {@code null} or empty then nothing is displayed. + * + * @return explanation text for for the wizard page + */ + protected abstract String getPageContextInformation(); + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + + // every time the page becomes visible, set the proper help context, this is required since + // the user could navigate back to the initial Eclipse import page which sets another help + // context + if (visible) { + if (getWizard() instanceof HelpContextIdProvider) { + String helpContextId = ((HelpContextIdProvider) getWizard()).getHelpContextId(); + PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), helpContextId); + } + } + } + + @Override + public void dispose() { + super.dispose(); + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeImportOptionsPreferencePage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeImportOptionsPreferencePage.java index c1e74bbc38..b570b5f936 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeImportOptionsPreferencePage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeImportOptionsPreferencePage.java @@ -12,29 +12,33 @@ import java.io.File; +import org.eclipse.core.runtime.Platform; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IWorkbenchPropertyPage; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.dialogs.PreferencesUtil; +import org.eclipse.ui.dialogs.PropertyPage; + import org.eclipse.buildship.core.internal.CorePlugin; import org.eclipse.buildship.core.internal.configuration.BuildConfiguration; +import org.eclipse.buildship.core.internal.configuration.CompositeConfiguration; import org.eclipse.buildship.core.internal.configuration.ConfigurationManager; +import org.eclipse.buildship.core.internal.configuration.DefaultCompositeConfiguration; import org.eclipse.buildship.core.internal.util.binding.Validator; import org.eclipse.buildship.core.internal.util.binding.Validators; import org.eclipse.buildship.ui.internal.util.gradle.GradleDistributionViewModel; import org.eclipse.buildship.ui.internal.util.widget.AdvancedOptionsGroup; import org.eclipse.buildship.ui.internal.util.widget.GradleProjectSettingsComposite; -import org.eclipse.core.resources.IProject; -import org.eclipse.core.runtime.Platform; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.events.SelectionListener; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.ui.dialogs.PreferencesUtil; -import org.eclipse.ui.dialogs.PropertyPage; /** * Preference page for composite import options. * * @author Sebastian Kuzniarz */ -public final class GradleCompositeImportOptionsPreferencePage extends PropertyPage { +public final class GradleCompositeImportOptionsPreferencePage extends PropertyPage implements IWorkbenchPropertyPage { public static final String PAGE_ID = "org.eclipse.buildship.ui.compositeImportOptionsProperties"; @@ -62,8 +66,10 @@ protected Control createContents(Composite parent) { } private void initValues() { - IProject project = getTargetProject(); - BuildConfiguration buildConfig = CorePlugin.configurationManager().loadProjectConfiguration(project).getBuildConfiguration(); + IWorkingSet composite = getTargetComposite(); + + BuildConfiguration buildConfig = CorePlugin.configurationManager().loadCompositeConfiguration(composite).getBuildConfiguration(); + boolean overrideWorkspaceSettings = buildConfig.isOverrideWorkspaceSettings(); this.gradleProjectSettingsComposite.getGradleDistributionGroup().setDistribution(GradleDistributionViewModel.from(buildConfig.getGradleDistribution())); this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setGradleUserHome(buildConfig.getGradleUserHome()); @@ -89,28 +95,30 @@ private void addListeners() { @Override public boolean performOk() { - IProject project = getTargetProject(); - ConfigurationManager manager = CorePlugin.configurationManager(); - BuildConfiguration currentConfig = manager.loadProjectConfiguration(project).getBuildConfiguration(); - BuildConfiguration updatedConfig = manager.createBuildConfiguration(currentConfig.getRootProjectDirectory(), - this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().getSelection(), - this.gradleProjectSettingsComposite.getGradleDistributionGroup().getDistribution().toGradleDistribution(), - this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getGradleUserHome(), - this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJavaHome(), - this.gradleProjectSettingsComposite.getBuildScansCheckbox().getSelection(), - this.gradleProjectSettingsComposite.getOfflineModeCheckbox().getSelection(), - this.gradleProjectSettingsComposite.getAutoSyncCheckbox().getSelection(), - this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getArguments(), - this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJvmArguments(), - this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().getSelection(), - this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().getSelection()); - manager.saveBuildConfiguration(updatedConfig); - return true; + IWorkingSet composite = getTargetComposite(); + ConfigurationManager manager = CorePlugin.configurationManager(); + CompositeConfiguration currentConfig = manager.loadCompositeConfiguration(composite); + + BuildConfiguration updatedConfig = manager.createBuildConfiguration(currentConfig.getBuildConfiguration().getRootProjectDirectory(), + this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().getSelection(), + this.gradleProjectSettingsComposite.getGradleDistributionGroup().getDistribution().toGradleDistribution(), + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getGradleUserHome(), + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJavaHome(), + this.gradleProjectSettingsComposite.getBuildScansCheckbox().getSelection(), + this.gradleProjectSettingsComposite.getOfflineModeCheckbox().getSelection(), + this.gradleProjectSettingsComposite.getAutoSyncCheckbox().getSelection(), + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getArguments(), + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJvmArguments(), + this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().getSelection(), + this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().getSelection()); + CompositeConfiguration compConf = new DefaultCompositeConfiguration(currentConfig.getCompositeDir(), composite.getElements(), updatedConfig, currentConfig.projectAsCompositeRoot() ,currentConfig.getRootProject()); + manager.saveCompositeConfiguration(compConf); + return true; } @SuppressWarnings("cast") - private IProject getTargetProject() { - return (IProject) Platform.getAdapterManager().getAdapter(getElement(), IProject.class); + private IWorkingSet getTargetComposite() { + return (IWorkingSet) Platform.getAdapterManager().getAdapter(getElement(), IWorkingSet.class); } /** diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeRootProjectPreferencePage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeRootProjectPreferencePage.java index 1afc18af35..60f563533c 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeRootProjectPreferencePage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeRootProjectPreferencePage.java @@ -10,9 +10,14 @@ package org.eclipse.buildship.ui.internal.preferences; +import java.io.File; + +import org.eclipse.core.runtime.Platform; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; @@ -21,8 +26,17 @@ import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbenchPropertyPage; +import org.eclipse.ui.IWorkingSet; import org.eclipse.ui.dialogs.PropertyPage; +import org.eclipse.buildship.core.internal.CorePlugin; +import org.eclipse.buildship.core.internal.configuration.CompositeConfiguration; +import org.eclipse.buildship.core.internal.configuration.ConfigurationManager; +import org.eclipse.buildship.core.internal.configuration.DefaultCompositeConfiguration; +import org.eclipse.buildship.core.internal.util.binding.Validator; +import org.eclipse.buildship.core.internal.util.binding.Validators; +import org.eclipse.buildship.ui.internal.util.file.DirectoryDialogSelectionListener; import org.eclipse.buildship.ui.internal.util.layout.LayoutUtils; import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeWizardMessages; @@ -32,16 +46,17 @@ * @author Sebastian Kuzniarz */ -public final class GradleCompositeRootProjectPreferencePage extends PropertyPage { +public final class GradleCompositeRootProjectPreferencePage extends PropertyPage implements IWorkbenchPropertyPage { public static final String PAGE_ID = "org.eclipse.buildship.ui.compositeRootProjectProperties"; private Text workspaceCompositeRootProjectLabel; - private Text overrideCheckboxLabel; - private Button overrideSettingsCheckbox; + private Button projectAsCompositeRootCheckbox; private Button selectRootProject; private Composite rootProjectSettingsComposite; private Label rootProjectLabel; + private final Validator rootProjectValidator; + CompositeConfiguration compositeConfig; private Layout createLayout() { GridLayout layout = LayoutUtils.newGridLayout(2); @@ -50,21 +65,31 @@ private Layout createLayout() { return layout; } + public GradleCompositeRootProjectPreferencePage() { + this.rootProjectValidator = Validators.optionalDirectoryValidator("Root project"); + } + @Override protected Control createContents(Composite parent) { + this.rootProjectSettingsComposite = buildRootProjectSettingsComposite(parent); + addListeners(); + initValues(); + return this.rootProjectSettingsComposite; + } - this.rootProjectSettingsComposite = new Composite(parent, SWT.NONE); - this.rootProjectSettingsComposite.setLayout(createLayout()); + private Composite buildRootProjectSettingsComposite(Composite parent) { + Composite rootProjectComposite = new Composite(parent, SWT.WRAP); + rootProjectComposite.setLayout(createLayout()); - this.overrideSettingsCheckbox = new Button(this.rootProjectSettingsComposite, SWT.CHECK); - this.overrideSettingsCheckbox.setText("Use project as composite root"); - GridDataFactory.swtDefaults().applyTo(this.rootProjectSettingsComposite); + this.projectAsCompositeRootCheckbox = new Button(rootProjectComposite, SWT.CHECK); + this.projectAsCompositeRootCheckbox.setText("Use project as composite root"); + GridDataFactory.swtDefaults().applyTo(rootProjectComposite); - Label line = new Label(this.rootProjectSettingsComposite, SWT.SEPARATOR | SWT.HORIZONTAL); + Label line = new Label(rootProjectComposite, SWT.SEPARATOR | SWT.HORIZONTAL); GridDataFactory.fillDefaults().align(SWT.FILL, SWT.CENTER).span(2, 1).applyTo(line); // composite root container - Composite workspaceCompositeNameComposite = new Composite(this.rootProjectSettingsComposite, SWT.NONE); + Composite workspaceCompositeNameComposite = new Composite(rootProjectComposite, SWT.NONE); GridLayoutFactory.swtDefaults().extendedMargins(0, 0, 0, 10).numColumns(3).applyTo(workspaceCompositeNameComposite); GridDataFactory.swtDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).span(3, SWT.DEFAULT).applyTo(workspaceCompositeNameComposite); @@ -72,16 +97,66 @@ protected Control createContents(Composite parent) { this.rootProjectLabel = new Label(workspaceCompositeNameComposite, SWT.NONE); this.rootProjectLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1)); this.rootProjectLabel.setText(WorkspaceCompositeWizardMessages.Label_RootProject); + this.rootProjectLabel.setEnabled(false); // root project text field this.workspaceCompositeRootProjectLabel = new Text(workspaceCompositeNameComposite, SWT.BORDER); this.workspaceCompositeRootProjectLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + this.workspaceCompositeRootProjectLabel.setEnabled(false); // root project select button this.selectRootProject = new Button(workspaceCompositeNameComposite, SWT.PUSH); this.selectRootProject.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); this.selectRootProject.setText(WorkspaceCompositeWizardMessages.Button_Select_RootProject); - return this.rootProjectSettingsComposite; + this.selectRootProject.setEnabled(false); + return rootProjectComposite; + } + + private void initValues() { + IWorkingSet composite = getTargetComposite(); + + this.compositeConfig = CorePlugin.configurationManager().loadCompositeConfiguration(composite); + boolean useProjectAsCompositeRoot = this.compositeConfig.projectAsCompositeRoot(); + + this.projectAsCompositeRootCheckbox.setSelection(useProjectAsCompositeRoot); + this.workspaceCompositeRootProjectLabel.setText(this.compositeConfig.getRootProject().toString()); + updateEnablement(); + } + + private void addListeners() { + if (this.projectAsCompositeRootCheckbox != null) { + this.projectAsCompositeRootCheckbox.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + updateEnablement(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + updateEnablement(); + } + }); + + File rootProjectDir = this.workspaceCompositeRootProjectLabel.getText().isEmpty() ? null: new File(this.workspaceCompositeRootProjectLabel.getText()); + this.workspaceCompositeRootProjectLabel.addModifyListener(new ValidatingListener<>(this, () -> rootProjectDir, this.rootProjectValidator)); + + this.selectRootProject.addSelectionListener(new DirectoryDialogSelectionListener(this.getShell(), this.workspaceCompositeRootProjectLabel, "Root project")); + } + } + + public void updateEnablement() { + if (this.projectAsCompositeRootCheckbox != null) { + boolean enabled = this.projectAsCompositeRootCheckbox.getSelection(); + this.rootProjectLabel.setEnabled(enabled); + this.selectRootProject.setEnabled(enabled); + this.workspaceCompositeRootProjectLabel.setEnabled(enabled); + } + } + + @SuppressWarnings("cast") + private IWorkingSet getTargetComposite() { + return (IWorkingSet) Platform.getAdapterManager().getAdapter(getElement(), IWorkingSet.class); } @Override @@ -91,6 +166,16 @@ public void dispose() { @Override public boolean performOk() { - return true; + IWorkingSet composite = getTargetComposite(); + ConfigurationManager manager = CorePlugin.configurationManager(); + CompositeConfiguration currentConfig = manager.loadCompositeConfiguration(composite); + + CompositeConfiguration compConf = new DefaultCompositeConfiguration(currentConfig.getCompositeDir(), + composite.getElements(), + currentConfig.getBuildConfiguration(), + this.projectAsCompositeRootCheckbox.getSelection(), + new File(this.workspaceCompositeRootProjectLabel.getText())); + manager.saveCompositeConfiguration(compConf); + return true; } } diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCreateWorkspaceCompositePreferencePage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCreateWorkspaceCompositePreferencePage.java new file mode 100644 index 0000000000..cee6afe401 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCreateWorkspaceCompositePreferencePage.java @@ -0,0 +1,299 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.preferences; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.eclipse.buildship.core.internal.CorePlugin; +import org.eclipse.buildship.ui.internal.util.layout.LayoutUtils; +import org.eclipse.buildship.ui.internal.util.widget.GradleProjectGroup; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.CompositeConfiguration; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.CompositeCreationConfiguration; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.CompositeCreationWizardController; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.CompositeImportWizardController; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.GradleImportOptionsWizardPage; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.IGradleCompositeIDs; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeCreationWizard; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeWizardMessages; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.layout.GridDataFactory; +import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.dialogs.IWorkingSetPage; + +import com.google.common.collect.ImmutableList; + +/** + * Page on the {@link WorkspaceCompositeCreationWizard} declaring the workspace + * composite name and included projects. + */ +public final class GradleCreateWorkspaceCompositePreferencePage extends AbstractPropertiesPage + implements IWorkingSetPage { + + private final CompositeCreationConfiguration creationConfiguration; + + @SuppressWarnings("unused") + private Text workspaceCompositeNameText; + private Label compositeName; + private GradleProjectGroup gradleProjectCheckboxtreeComposite; + + private static IWorkingSet gradleComposite; + private boolean firstCheck; + private static CompositeImportWizardController importController; + + public GradleCreateWorkspaceCompositePreferencePage(CompositeConfiguration importConfiguration, + CompositeCreationConfiguration creationConfiguration) { + super("NewGradleWorkspaceComposite", //$NON-NLS-1$ + WorkspaceCompositeWizardMessages.Title_NewGradleWorkspaceCompositeWizardPage, + WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault, importConfiguration, ImmutableList.of(creationConfiguration.getCompositeName(), + creationConfiguration.getCompositeProjects())); + gradleComposite = null; + this.creationConfiguration = creationConfiguration; + this.firstCheck = true; + } + + public GradleCreateWorkspaceCompositePreferencePage() { + this(getCompositeImportConfiguration(), getCompositeCreationConfiguration()); + } + + private IWizardPage buildImportOptionsWizardPage() { + IWizardPage page = new GradleImportOptionsWizardPage(getConfiguration()); + page.setWizard(getWizard()); + return page; + } + + protected String getPageId() { + return "org.eclipse.buildship.ui.GradleCompositePage"; //$NON-NLS-1$ + } + + private static CompositeCreationConfiguration getCompositeCreationConfiguration() { + ArrayList compositeElements = new ArrayList<>(); + String compositeName = gradleComposite != null ? gradleComposite.getName() : ""; + CompositeCreationWizardController creationController = new CompositeCreationWizardController(compositeName, compositeElements); + return creationController.getConfiguration(); + } + + private static CompositeConfiguration getCompositeImportConfiguration() { + importController = new CompositeImportWizardController(null); + return importController.getConfiguration(); + } + + @Override + public void createControl(Composite parent) { + super.createControl(parent); + } + + @Override + protected void createWidgets(Composite root) { + root.setLayout(LayoutUtils.newGridLayout(3)); + createContent(root); + } + + private void createContent(Composite root) { + + // composite name container + Composite workspaceCompositeNameComposite = new Composite(root, SWT.FILL); + GridLayoutFactory.fillDefaults().extendedMargins(0, 0, 0, 5).numColumns(2) + .applyTo(workspaceCompositeNameComposite); + GridDataFactory.fillDefaults().align(SWT.FILL, SWT.TOP).grab(true, false).span(3, SWT.DEFAULT) + .applyTo(workspaceCompositeNameComposite); + + // composite name label + this.compositeName = new Label(workspaceCompositeNameComposite, SWT.NONE); + this.compositeName.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1)); + this.compositeName.setText(WorkspaceCompositeWizardMessages.Label_CompositeName); + + // composite name text field + this.workspaceCompositeNameText = new Text(workspaceCompositeNameComposite, SWT.BORDER); + this.workspaceCompositeNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + + this.gradleProjectCheckboxtreeComposite = new GradleProjectGroup(root, (gradleComposite != null)); + GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).span(3, SWT.DEFAULT) + .applyTo(this.gradleProjectCheckboxtreeComposite); + + addListeners(); + + if (gradleComposite != null) { + this.workspaceCompositeNameText.setText(gradleComposite.getName()); + } + } + + private void addListeners() { + this.workspaceCompositeNameText.addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + updateLocation(); + validateInput(); + } + }); + this.gradleProjectCheckboxtreeComposite.getCheckboxTree().addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event event) { + updateCompositeProjects(); + validateInput(); + } + }); + } + + protected void updateCompositeProjects() { + List projectList = new ArrayList<>(); + + for (TreeItem treeElement : this.gradleProjectCheckboxtreeComposite.getCheckboxTree().getItems()) { + if (treeElement.getChecked() == true) { + if (treeElement.getText().contains(" (External): ")) { + //String[] treeValues = treeElement.getText().replace(" (External): ", "$").split("\\$"); + // treeValues[0] contains the project name + // treeValues[1] contains the file path + //File externalFolder = new File(treeValues[1]); + projectList.add(null); + } else { + projectList.add(ResourcesPlugin.getWorkspace().getRoot().getProject(treeElement.getText())); + } + } + } + getConfiguration().getProjectList().setValue(projectList.toArray(new IAdaptable[projectList.size()])); + this.creationConfiguration.setCompositeProjects(projectList); + } + + private void updateLocation() { + File parentLocation = CorePlugin.getInstance().getStateLocation().append("workspace-composites").toFile(); + File projectDir = parentLocation != null ? new File(parentLocation, this.workspaceCompositeNameText.getText()) + : null; + + // always update project name last to ensure project name validation errors have + // precedence in the UI + getConfiguration().getCompositePreferencesDir().setValue(projectDir); + this.creationConfiguration.setCompositeName(this.workspaceCompositeNameText.getText()); + } + + @Override + protected String getPageContextInformation() { + return WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeWizardPageContext; + } + + @Override + public void finish() { + updateCompositeProjects(); + String workspaceCompositeName = this.workspaceCompositeNameText.getText(); + IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager(); + + try { + File compositePreferenceFile = CorePlugin.getInstance().getStateLocation() + .append("workspace-composites").append(workspaceCompositeName).toFile(); + + if (gradleComposite == null) { + gradleComposite = workingSetManager.createWorkingSet(workspaceCompositeName, + getConfiguration().getProjectList().getValue()); + gradleComposite.setId(IGradleCompositeIDs.NATURE); + } else { + IAdaptable[] oldElements = gradleComposite.getElements(); + if (!gradleComposite.getName().equals(this.workspaceCompositeNameText.getText())) { + gradleComposite.setName(this.workspaceCompositeNameText.getText()); + } + + if (!oldElements.equals(getConfiguration().getProjectList().getValue())) { + gradleComposite.setElements(getConfiguration().getProjectList().getValue()); + } + } + FileOutputStream out = new FileOutputStream(compositePreferenceFile.getAbsoluteFile()); + Properties prop = getConfiguration().toCompositeProperties().toProperties(); + prop.store(out, " "); + out.close(); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + @Override + public IWorkingSet getSelection() { + return gradleComposite; + } + + @Override + public void setSelection(IWorkingSet workingSet) { + Assert.isNotNull(workingSet, "Composite must not be null"); //$NON-NLS-1$ + gradleComposite = workingSet; + if (getContainer() == null && getShell() != null && this.workspaceCompositeNameText != null) { + this.workspaceCompositeNameText.setText(gradleComposite.getName()); + } + } + + @Override + public IWizardPage getNextPage() { + return buildImportOptionsWizardPage(); + } + + protected void validateInput() { + String errorMessage = null; + String infoMessage = null; + String newText= this.workspaceCompositeNameText.getText(); + + if (newText.equals(newText.trim()) == false) { + errorMessage = WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_NameWhitespaces; + } + if (newText.isEmpty()) { + if (this.firstCheck) { + setPageComplete(false); + this.firstCheck= false; + return; + } else { + errorMessage = WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_NameEmpty; + } + } + + this.firstCheck= false; + + if (errorMessage == null && (gradleComposite == null || newText.equals(gradleComposite.getName()) == false)) { + IWorkingSet[] workingSets= PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets(); + for (int i= 0; i < workingSets.length; i++) { + if (newText.equals(workingSets[i].getName())) { + errorMessage= WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_CompositeNameExists; + } + } + } + + if (!hasSelectedElement()) { + infoMessage = WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_CompositeEmpty; + } + + setMessage(infoMessage, INFORMATION); + setErrorMessage(errorMessage); + setPageComplete(errorMessage == null); + } + + private boolean hasSelectedElement() { + return this.creationConfiguration.getCompositeProjects().getValue().size() > 0; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleDistributionValidatingListener.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleDistributionValidatingListener.java index 5ca331192d..b1ce49d8a6 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleDistributionValidatingListener.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleDistributionValidatingListener.java @@ -22,7 +22,7 @@ * * @author Donat Csikos */ -final class GradleDistributionValidatingListener implements DistributionChangedListener { +public final class GradleDistributionValidatingListener implements DistributionChangedListener { private final PreferencePage preferencePage; private final Validator distributionValidator; diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleProjectPreferencePage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleProjectPreferencePage.java index 53517a5534..7536005a30 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleProjectPreferencePage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleProjectPreferencePage.java @@ -110,7 +110,7 @@ public boolean performOk() { return true; } - @SuppressWarnings({"cast", "RedundantCast"}) + @SuppressWarnings({"cast"}) private IProject getTargetProject() { return (IProject) Platform.getAdapterManager().getAdapter(getElement(), IProject.class); } diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleWorkspaceCompositePreferencePage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleWorkspaceCompositePreferencePage.java index 63d52f0aa1..d43ef95e2a 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleWorkspaceCompositePreferencePage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleWorkspaceCompositePreferencePage.java @@ -58,7 +58,11 @@ protected Control createContents(Composite parent) { this.workspaceCompositeNameText = new Text(workspaceCompositeNameComposite, SWT.BORDER); this.workspaceCompositeNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); +<<<<<<< HEAD this.gradleProjectCheckboxtreeComposite = new GradleProjectGroup(this.gradleWorkspaceCompositeSettingsComposite); +======= + this.gradleProjectCheckboxtreeComposite = new GradleProjectGroup(this.gradleWorkspaceCompositeSettingsComposite, true); +>>>>>>> kuzniarz-workspace-composites-rebased GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).span(3, SWT.DEFAULT).applyTo(this.gradleProjectCheckboxtreeComposite); return this.gradleWorkspaceCompositeSettingsComposite; @@ -66,6 +70,10 @@ protected Control createContents(Composite parent) { @Override public boolean performOk() { +<<<<<<< HEAD return true; +======= + return true; +>>>>>>> kuzniarz-workspace-composites-rebased } } diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/ValidatingListener.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/ValidatingListener.java index 34dded78f7..27a53d0b55 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/ValidatingListener.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/ValidatingListener.java @@ -23,7 +23,7 @@ * * @author Donat Csikos */ -final class ValidatingListener implements ModifyListener { +public final class ValidatingListener implements ModifyListener { private final PreferencePage preferencePage; private final Supplier target; diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/file/ExternalProjectDialogSelectionListener.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/file/ExternalProjectDialogSelectionListener.java new file mode 100644 index 0000000000..4a5e611311 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/file/ExternalProjectDialogSelectionListener.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.util.file; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import com.google.common.base.Preconditions; + +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.TreeItem; + +import org.eclipse.buildship.ui.internal.i18n.UiMessages; + +public class ExternalProjectDialogSelectionListener extends SelectionAdapter { + + private final Shell shell; + private final TreeViewer projectTreeViewer; + private final String title; + private final Map externalProjectPaths; + + public ExternalProjectDialogSelectionListener(Shell shell, TreeViewer treeViewer, String entity) { + + this.shell = Preconditions.checkNotNull(shell); + this.projectTreeViewer = treeViewer; + this.title = NLS.bind(UiMessages.Title_Select_0, entity); + ColumnViewerToolTipSupport.enableFor(this.projectTreeViewer); + this.externalProjectPaths = new HashMap<>(); + } + + @Override + public void widgetSelected(SelectionEvent e) { + DirectoryDialog directoryDialog = new DirectoryDialog(this.shell, SWT.SHEET); + directoryDialog.setText(this.title); + + String userHomeDir = System.getProperty("user.home"); + directoryDialog.setFilterPath(userHomeDir); + + String selectedDirectory = directoryDialog.open(); + if (selectedDirectory != null) { + addExternalProjectToProjectTree(selectedDirectory); + } + } + + private void addExternalProjectToProjectTree(String selectedDirectory) { + String projectDir = selectedDirectory; + File gradleSettingsFile = getGradleSettings(projectDir); + if (gradleSettingsFile.isFile()) { + try { + FileInputStream inputStream = new FileInputStream(gradleSettingsFile); + Properties gradleSettings = new Properties(); + gradleSettings.load(inputStream); + String projectName = getProjectName(gradleSettings); + TreeItem jItem = new TreeItem(this.projectTreeViewer.getTree(), 0); + jItem.setFont(JFaceResources.getFontRegistry().getItalic(JFaceResources.DEFAULT_FONT)); + jItem.setChecked(true); + jItem.setText(projectName + " (External): " + gradleSettingsFile.getParentFile().getPath()); + if (!this.externalProjectPaths.containsKey(gradleSettingsFile.getParentFile().getPath())) { + this.externalProjectPaths.put(gradleSettingsFile.getParentFile().getPath(), projectName); + } + } catch (IOException e) { + e.printStackTrace(); + } + } else { + MessageBox dialog = new MessageBox(this.shell, SWT.ICON_ERROR | SWT.OK); + dialog.setText("Error"); + dialog.setMessage("The selected directory is not a gradle project dir!"); + dialog.open(); + } + } + + private String getProjectName(Properties gradleSettings) { + //Refactored method to include String cleaning + return gradleSettings.get("rootProject.name").toString().replaceAll("'", "").replaceAll("\"", ""); + } + + private File getGradleSettings(String projectDir) { + File groovyFile = new File(projectDir + "\\settings.gradle"); + File kotlinFile = new File(projectDir + "\\settings.gradle.kts"); + if (groovyFile.exists()) { + return groovyFile; + } else if (kotlinFile.exists()) { + return kotlinFile; + } else { + return new File(""); + } + } + + public Map getExternalProjectPaths() { + return this.externalProjectPaths; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/GradleProjectGroup.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/GradleProjectGroup.java index c23d4511b5..b2094deda1 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/GradleProjectGroup.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/GradleProjectGroup.java @@ -10,8 +10,25 @@ package org.eclipse.buildship.ui.internal.util.widget; +import java.util.ArrayList; +import java.util.Map; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IWorkspaceRoot; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.BusyIndicator; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; @@ -19,7 +36,15 @@ import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Tree; import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.PlatformUI; +import org.eclipse.buildship.core.internal.configuration.GradleProjectNature; +import org.eclipse.buildship.ui.internal.util.file.ExternalProjectDialogSelectionListener; +import org.eclipse.buildship.ui.internal.wizard.project.ProjectCreationWizard; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.IGradleCompositeIDs; import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeWizardMessages; @SuppressWarnings("unused") @@ -28,12 +53,15 @@ public class GradleProjectGroup extends Group { private Font font; private Button newGradleProject; private Button addExternalGradleProject; + private ExternalProjectDialogSelectionListener externalProjectListener; private Composite buttonComposite; - private Tree gradleProjectTree; + private TreeViewer gradleProjectTree; + private boolean editMode; - public GradleProjectGroup(Composite parent) { + public GradleProjectGroup(Composite parent, boolean editMode) { super(parent, SWT.NONE); setText(WorkspaceCompositeWizardMessages.Group_Label_GradleProjects); + this.editMode = editMode; createWidgets(); } @@ -41,8 +69,14 @@ public void createWidgets() { setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); GridLayoutFactory.swtDefaults().numColumns(4).applyTo(this); - this.gradleProjectTree = new Tree(this, SWT.CHECK); - this.gradleProjectTree.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); + this.gradleProjectTree = new TreeViewer(this, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.CHECK); + this.gradleProjectTree.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1)); + fillCheckboxTreeWithProjects(); + if (this.editMode) { + configureTree(); + } + + this.gradleProjectTree.setUseHashlookup(true); this.buttonComposite = new Composite(this, SWT.NONE); this.buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true, 1, 1)); @@ -56,28 +90,122 @@ public void createWidgets() { this.addExternalGradleProject.setText(WorkspaceCompositeWizardMessages.Button_Add_ExternalGradleProject); this.addExternalGradleProject.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - fillCheckboxTreeWithFakeData(); + addListener(); + } + + private void addListener() { + this.newGradleProject.addSelectionListener(new SelectionAdapter() { + + @Override + public void widgetSelected(SelectionEvent e) { + WizardDialog wizard = new WizardDialog(getShell(), new ProjectCreationWizard()); + if (wizard.open() == WizardDialog.OK) { + fillCheckboxTreeWithProjects(); + configureTree(); + } + } + }); + this.externalProjectListener = new ExternalProjectDialogSelectionListener(getShell(), this.gradleProjectTree, ""); + this.addExternalGradleProject.addSelectionListener(this.externalProjectListener); } - private void fillCheckboxTreeWithFakeData() { - for (int i = 0; i < 4; i++) { - TreeItem iItem = new TreeItem(this.gradleProjectTree, 0); - iItem.setText("TreeItem (0) -" + i); - for (int j = 0; j < 4; j++) { - TreeItem jItem = new TreeItem(iItem, 0); - jItem.setText("TreeItem (1) -" + j); - for (int k = 0; k < 4; k++) { - TreeItem kItem = new TreeItem(jItem, 0); - kItem.setText("TreeItem (2) -" + k); - for (int l = 0; l < 4; l++) { - TreeItem lItem = new TreeItem(kItem, 0); - lItem.setText("TreeItem (3) -" + l); + private void configureTree() { + + ArrayList selection = getInitialTreeSelection(); + + try { + this.gradleProjectTree.getTree().setRedraw(false); + for (TreeItem item : this.gradleProjectTree.getTree().getItems()) { + if (selection.contains(item.getText())) { + item.setChecked(true); + } + } + } finally { + this.gradleProjectTree.getTree().setRedraw(true); + } + + } + + public boolean hasSelectedItems() { + return this.gradleProjectTree.getTree().getSelectionCount() > 0; + } + + private ArrayList getInitialTreeSelection() { + ArrayList projectNames = new ArrayList<>(); + BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() { + + @Override + public void run() { + IStructuredSelection projectSelection = null; + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + if (page == null) { + return; + } + + IWorkbenchPart part = page.getActivePart(); + if (part == null) { + return; + } + + try { + ISelectionProvider provider = part.getSite().getSelectionProvider(); + if (provider != null) { + ISelection selection = provider.getSelection(); + projectSelection = selection instanceof IStructuredSelection ? (IStructuredSelection) selection : StructuredSelection.EMPTY; + } + } catch (Exception e) { + return; + } + + Object[] elements = projectSelection.toArray(); + + for (int i = 0; i < elements.length; i++) { + if (elements[i] instanceof IWorkingSet) { + IWorkingSet ge = ((IWorkingSet) elements[i]); + if (ge != null && ge.getId().equals(IGradleCompositeIDs.NATURE)) { + for (int j = 0; j < ge.getElements().length; j++) { + IAdaptable[] element = ge.getElements(); + projectNames.add(((IAdaptable) element[j]).getAdapter(IProject.class).getName()); + } + elements[i] = projectNames; + } } } } + }); + + return projectNames; + } + + private void fillCheckboxTreeWithProjects() { + this.gradleProjectTree.getTree().removeAll(); + try { + IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot(); + IProject[] projects = workspaceRoot.getProjects(); + for (int i = 0; i < projects.length; i++) { + IProject project = projects[i]; + if (project.hasNature(GradleProjectNature.ID)) { + TreeItem jItem = new TreeItem(this.gradleProjectTree.getTree(), 0); + jItem.setText(project.getName()); + } + } + } catch (CoreException ce) { + ce.printStackTrace(); } } + public Tree getCheckboxTree() { + return this.gradleProjectTree.getTree(); + } + + public TreeViewer getCheckboxTreeViewer() { + return this.gradleProjectTree; + } + + public Map getExternalProjectPathList() { + return this.externalProjectListener.getExternalProjectPaths(); + } + @Override protected void checkSubclass() { // Disable the check that prevents subclassing of SWT components diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/view/task/RemoveComposite.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/view/task/RemoveComposite.java new file mode 100644 index 0000000000..0baf576549 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/view/task/RemoveComposite.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.view.task; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.core.commands.IHandlerListener; + +public class RemoveComposite implements IHandler { + + @Override + public void addHandlerListener(IHandlerListener handlerListener) { + // TODO Auto-generated method stub + + } + + @Override + public void dispose() { + // TODO Auto-generated method stub + + } + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean isEnabled() { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isHandled() { + // TODO Auto-generated method stub + return false; + } + + @Override + public void removeHandlerListener(IHandlerListener handlerListener) { + // TODO Auto-generated method stub + + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractCompositeWizardPage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractCompositeWizardPage.java new file mode 100644 index 0000000000..f5cf0082df --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractCompositeWizardPage.java @@ -0,0 +1,234 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.util.List; + +import com.google.common.base.Optional; +import com.google.common.base.Strings; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.ui.PlatformUI; + +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.core.internal.util.binding.ValidationListener; +import org.eclipse.buildship.ui.internal.wizard.HelpContextIdProvider; + +/** + * Common base class for all pages in the {@link WorkspaceCompositeCreationWizard}. + */ +public abstract class AbstractCompositeWizardPage extends WizardPage { + + private final CompositeConfiguration configuration; + private final List> observedProperties; + private final String defaultMessage; + + /** + * Constructor setting up the main messages and the validation facility for this wizard page. + * + * @param name the name of the page + * @param title the page title + * @param defaultMessage the default message to show when there is no validation error + * @param configuration the data model of the wizard + * @param observedProperties the subset of the properties from the data model that are managed + * on this page + */ + protected AbstractCompositeWizardPage(String name, String title, String defaultMessage, CompositeConfiguration configuration, final List> observedProperties) { + super(name); + + this.configuration = configuration; + this.observedProperties = observedProperties; + this.defaultMessage = defaultMessage; + + // set the basic message and the attached image + setTitle(title); + setMessage(defaultMessage); + setImageDescriptor(ImageDescriptor.createFromFile(GradleCreateWorkspaceCompositeWizardPage.class, "/icons/full/wizban/wizard.png")); //$NON-NLS-1$ + + // create a listener that updates the state and the message if an observed property in the + // model changes + ValidationListener listener = new ValidationListener() { + @Override + public void validationTriggered(Property source, Optional validationErrorMessage) { + validateInput(source, validationErrorMessage); + // we set the page to completed if all its properties are valid + setPageComplete(isPageComplete()); + } + }; + + // attach the listener to all of the observed properties + for (Property property : observedProperties) { + property.addValidationListener(listener); + } + } + /** + * This method is overided by the main composite creation page due to a different validation machanism. + * @param source + * @param validationErrorMessage + */ + protected void validateInput(Property source, Optional validationErrorMessage) { + // if the modified property is invalid, show its error message, otherwise check if + // any of the other properties of this page is invalid and if so, display the first + // found error message + if (validationErrorMessage.isPresent()) { + setMessage(validationErrorMessage.get(), IMessageProvider.ERROR); + } else { + Optional otherErrorMessage = validateAllObservedProperties(); + if (!otherErrorMessage.isPresent()) { + setMessage(AbstractCompositeWizardPage.this.defaultMessage); + } else { + setMessage(otherErrorMessage.get(), IMessageProvider.ERROR); + } + } + } + + private Optional validateAllObservedProperties() { + for (Property property : this.observedProperties) { + Optional errorMessage = property.validate(); + if (errorMessage.isPresent()) { + return errorMessage; + } + } + return Optional.absent(); + } + + protected CompositeConfiguration getConfiguration() { + return this.configuration; + } + + protected List> getObservedProperties() { + return this.observedProperties; + } + + @Override + public final void createControl(Composite parent) { + // align dialog units to the current resolution + initializeDialogUnits(parent); + + // create the container control + Composite pageControl = createWizardPageContent(parent); + + // assign the created control to the wizard page + setControl(pageControl); + } + + private Composite createWizardPageContent(Composite parent) { + // create a scrollable root to handle resizing + ScrolledComposite externalRoot = new ScrolledComposite(parent, SWT.H_SCROLL | SWT.V_SCROLL); + externalRoot.setExpandHorizontal(true); + externalRoot.setExpandVertical(true); + externalRoot.setMinSize(new Point(230, 380)); + + // add the controls inside the root composite + Composite container = new Composite(externalRoot, SWT.NONE); + createWidgets(container); + + // add context information to the bottom of the page if the page defines it + String contextInformation = Strings.emptyToNull(getPageContextInformation()); + if (contextInformation != null) { + createWidgetsForContextInformation(container, contextInformation); + } + + // also compute the size of the container, otherwise the ScrolledComposite's content is not + // rendered properly + Point containerSize = container.computeSize(SWT.DEFAULT, SWT.DEFAULT); + container.setSize(containerSize); + + // set the root's content and return it + externalRoot.setContent(container); + return externalRoot; + } + + /** + * Populates the widgets in the wizard page. + */ + protected abstract void createWidgets(Composite root); + + private void createWidgetsForContextInformation(Composite root, String contextInformation) { + // create a container box occupying all horizontal space and has a 1-column row layout and a + // 30 pixel margin to not stretch the separator widgets to the edge of the wizard page + Composite contextInformationContainer = new Composite(root, SWT.NONE); + GridLayout contextInformationContainerLayout = new GridLayout(1, false); + contextInformationContainerLayout.marginLeft = contextInformationContainerLayout.marginRight = contextInformationContainerLayout.marginTop = 30; + contextInformationContainerLayout.verticalSpacing = 15; + contextInformationContainer.setLayout(contextInformationContainerLayout); + contextInformationContainer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 3, 1)); + + // separator widget + Label separator = new Label(contextInformationContainer, SWT.HORIZONTAL | SWT.SEPARATOR); + separator.setLayoutData(new GridData(SWT.FILL, SWT.BOTTOM, true, false)); + + // internal container for flexible resize + Composite textContainer = new Composite(contextInformationContainer, SWT.NONE); + textContainer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false, 1, 1)); + GridLayout textContainerLayout = new GridLayout(1, false); + textContainerLayout.marginLeft = textContainerLayout.marginRight = 50; + textContainer.setLayout(textContainerLayout); + + // text widget aligned to the center having 400 pixels allocated for each line of content + StyledText contextInformationText = new StyledText(textContainer, SWT.WRAP | SWT.MULTI | SWT.CENTER); + contextInformationText.setText(contextInformation); + contextInformationText.setBackground(contextInformationText.getParent().getBackground()); + contextInformationText.setEnabled(false); + contextInformationText.setEditable(false); + GridData contextInformationTextLayoutData = new GridData(SWT.CENTER, SWT.CENTER, true, false, 1, 1); + contextInformationTextLayoutData.widthHint = 400; + contextInformationText.setLayoutData(contextInformationTextLayoutData); + } + + /** + * Returns text to display under the widgets. If {@code null} or empty then nothing is displayed. + * + * @return explanation text for for the wizard page + */ + protected abstract String getPageContextInformation(); + + @Override + public void setVisible(boolean visible) { + super.setVisible(visible); + + // every time the page becomes visible, set the proper help context, this is required since + // the user could navigate back to the initial Eclipse import page which sets another help + // context + if (visible) { + if (getWizard() instanceof HelpContextIdProvider) { + String helpContextId = ((HelpContextIdProvider) getWizard()).getHelpContextId(); + PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), helpContextId); + } + } + } + + @Override + public boolean isPageComplete() { + for (Property property : this.observedProperties) { + if (!property.isValid()) { + return false; + } + } + return true; + } + + @Override + public void dispose() { + super.dispose(); + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractWorkspaceCompositeWizard.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractWorkspaceCompositeWizard.java index e2022669c9..adc1a2b12a 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractWorkspaceCompositeWizard.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/AbstractWorkspaceCompositeWizard.java @@ -10,48 +10,34 @@ package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; -import org.eclipse.buildship.core.internal.GradlePluginsRuntimeException; -import org.eclipse.buildship.ui.internal.UiPlugin; -import org.eclipse.buildship.ui.internal.wizard.HelpContextIdProvider; +import org.osgi.service.prefs.BackingStoreException; + import org.eclipse.core.runtime.preferences.ConfigurationScope; import org.eclipse.core.runtime.preferences.IEclipsePreferences; import org.eclipse.jface.wizard.Wizard; -import org.osgi.service.prefs.BackingStoreException; -import com.google.common.base.Preconditions; +import org.eclipse.buildship.core.internal.GradlePluginsRuntimeException; +import org.eclipse.buildship.ui.internal.UiPlugin; +import org.eclipse.buildship.ui.internal.wizard.HelpContextIdProvider; /** * Base class for project wizards. */ public abstract class AbstractWorkspaceCompositeWizard extends Wizard implements HelpContextIdProvider { - // the preference key under which it is stored whether to show the welcome page or not - private final String welcomePageEnabledPreferenceKey; - // state bit storing that the wizard is blocked to finish globally private boolean finishGloballyEnabled; - protected AbstractWorkspaceCompositeWizard(String welcomePageEnabledPreferenceKey) { - this.welcomePageEnabledPreferenceKey = Preconditions.checkNotNull(welcomePageEnabledPreferenceKey); + protected AbstractWorkspaceCompositeWizard() { // the wizard must not be finishable unless this global flag is enabled this.finishGloballyEnabled = true; } - public boolean isShowWelcomePage() { - // store the in the configuration scope to have the same settings for - // all workspaces - @SuppressWarnings("deprecation") - ConfigurationScope configurationScope = new ConfigurationScope(); - IEclipsePreferences node = configurationScope.getNode(UiPlugin.PLUGIN_ID); - return node.getBoolean(this.welcomePageEnabledPreferenceKey, true); - } - public void setWelcomePageEnabled(boolean enabled) { @SuppressWarnings("deprecation") ConfigurationScope configurationScope = new ConfigurationScope(); IEclipsePreferences node = configurationScope.getNode(UiPlugin.PLUGIN_ID); - node.putBoolean(this.welcomePageEnabledPreferenceKey, enabled); try { node.flush(); } catch (BackingStoreException e) { diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeConfiguration.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeConfiguration.java new file mode 100644 index 0000000000..1335f86147 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeConfiguration.java @@ -0,0 +1,227 @@ +/******************************************************************************* + * Copyright (c) 2019 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.io.File; +import java.util.List; + +import org.eclipse.buildship.core.CompositeProperties; +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.core.internal.util.binding.Validator; +import org.eclipse.buildship.core.internal.util.binding.Validators; +import org.eclipse.buildship.ui.internal.util.gradle.GradleDistributionViewModel; +import org.eclipse.core.runtime.IAdaptable; + +/** + * Serves as the data model of the composite import wizard. + */ +public final class CompositeConfiguration { + + private final Property compositePreferencesDir; + private final Property projectList; + private final Property overwriteWorkspaceSettings; + private final Property distribution; + private final Property gradleUserHome; + private final Property javaHome; + private final Property applyWorkingSets; + private final Property> workingSets; + private final Property buildScansEnabled; + private final Property offlineMode; + private final Property autoSync; + private final Property> arguments; + private final Property> jvmArguments; + private final Property showConsoleView; + private final Property showExecutionsView; + private final Property projectAsCompositeRoot; + private final Property rootProject; + + public CompositeConfiguration() { + this(Validators.noOp(), Validators.noOp(), Validators.noOp(), Validators.noOp(), Validators.noOp(), Validators.>noOp(), Validators.noOp()); + } + + public CompositeConfiguration(Validator compositePreferencesDirValidator, Validator distributionValidator, + Validator gradleUserHomeValidator, Validator javaHomeValidator, Validator applyWorkingSetsValidator, Validator> workingSetsValidators, Validator rootProjectValidator) { + this.compositePreferencesDir = Property.create(compositePreferencesDirValidator); + this.projectList = Property.create(Validators.noOp()); + this.overwriteWorkspaceSettings = Property.create(Validators.noOp()); + this.distribution = Property.create(distributionValidator); + this.gradleUserHome = Property.create(gradleUserHomeValidator); + this.javaHome = Property.create(javaHomeValidator); + this.applyWorkingSets = Property.create(applyWorkingSetsValidator); + this.workingSets = Property.create(workingSetsValidators); + this.buildScansEnabled = Property.create(Validators.noOp()); + this.offlineMode = Property.create(Validators.noOp()); + this.autoSync = Property.create(Validators.noOp()); + this.arguments = Property.>create(Validators.>noOp()); + this.jvmArguments = Property.>create(Validators.>noOp()); + this.showConsoleView = Property.create(Validators.noOp()); + this.showExecutionsView = Property.create(Validators.noOp()); + this.projectAsCompositeRoot = Property.create(Validators.noOp()); + this.rootProject = Property.create(rootProjectValidator); + + } + + public Property getCompositePreferencesDir() { + return this.compositePreferencesDir; + } + + public void setCompositePreferencesDir(File compositePreferencesDir) { + this.compositePreferencesDir.setValue(compositePreferencesDir); + } + + public Property getProjectList() { + return this.projectList; + } + + public void setProjectList(IAdaptable[] projectList) { + this.projectList.setValue(projectList); + } + + public Property getOverrideWorkspaceConfiguration() { + return this.overwriteWorkspaceSettings; + } + + public void setOverwriteWorkspaceSettings(boolean overwriteWorkspaceSettings) { + this.overwriteWorkspaceSettings.setValue(Boolean.valueOf(overwriteWorkspaceSettings)); + } + + public Property getDistribution() { + return this.distribution; + } + + public void setDistribution(GradleDistributionViewModel distribution) { + this.distribution.setValue(distribution); + } + + public Property getGradleUserHome() { + return this.gradleUserHome; + } + + public void setGradleUserHome(File gradleUserHome) { + this.gradleUserHome.setValue(gradleUserHome); + } + + public Property getJavaHome() { + return this.javaHome; + } + + public void setJavaHomeHome(File javaHome) { + this.javaHome.setValue(javaHome); + } + + public Property getApplyWorkingSets() { + return this.applyWorkingSets; + } + + public void setApplyWorkingSets(Boolean applyWorkingSets) { + this.applyWorkingSets.setValue(applyWorkingSets); + } + + public Property> getWorkingSets() { + return this.workingSets; + } + + public void setWorkingSets(List workingSets) { + this.workingSets.setValue(workingSets); + } + + public Property getBuildScansEnabled() { + return this.buildScansEnabled; + } + + public void setBuildScansEnabled(boolean buildScansEnabled) { + this.buildScansEnabled.setValue(Boolean.valueOf(buildScansEnabled)); + } + + public Property getOfflineMode() { + return this.offlineMode; + } + + public void setOfflineMode(boolean offlineMode) { + this.offlineMode.setValue(Boolean.valueOf(offlineMode)); + } + + public Property getAutoSync() { + return this.autoSync; + } + + public void setAutoSync(boolean autoSync) { + this.autoSync.setValue(Boolean.valueOf(autoSync)); + } + + public Property> getArguments() { + return this.arguments; + } + + public void setArguments(List arguments) { + this.arguments.setValue(arguments); + } + + public Property> getJvmArguments() { + return this.jvmArguments; + } + + public void setJvmArguments(List jvmArguments) { + this.jvmArguments.setValue(jvmArguments); + } + + public Property getShowConsoleView() { + return this.showConsoleView; + } + + public void setShowConsoleView(boolean showConsoleView) { + this.showConsoleView.setValue(Boolean.valueOf(showConsoleView)); + } + + public Property getShowExecutionsView() { + return this.showExecutionsView; + } + + public void setShowExecutionsView(boolean showExecutionsView) { + this.showExecutionsView.setValue(Boolean.valueOf(showExecutionsView)); + } + + public Property getProjectAsCompositeRoot() { + return this.projectAsCompositeRoot; + } + + public void setProjectAsCompositeRoot(boolean overwriteRootProject) { + this.projectAsCompositeRoot.setValue(Boolean.valueOf(overwriteRootProject)); + } + + public Property getRootProject() { + return this.rootProject; + } + + public void setRootProject(File rootProject) { + this.rootProject.setValue(rootProject); + } + + public CompositeProperties toCompositeProperties() { + return CompositeProperties.forRootProjectDirectory(getCompositePreferencesDir().getValue()) + .projectList(getProjectList().getValue()) + .overrideWorkspaceConfiguration(getOverrideWorkspaceConfiguration().getValue()) + .gradleDistribution(getDistribution().getValue().toGradleDistribution()) + .gradleUserHome(getGradleUserHome().getValue()) + .javaHome(getJavaHome().getValue()) + .buildScansEnabled(getBuildScansEnabled().getValue()) + .offlineMode(getOfflineMode().getValue()) + .autoSync(getAutoSync().getValue()) + .arguments(getArguments().getValue()) + .jvmArguments(getJvmArguments().getValue()) + .showConsoleView(getShowConsoleView().getValue()) + .showExecutionsView(getShowExecutionsView().getValue()) + .projectAsCompositeRoot(getProjectAsCompositeRoot().getValue()) + .rootProject(getRootProject().getValue()) + .build(); + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationConfiguration.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationConfiguration.java new file mode 100644 index 0000000000..3c3e5bc3b2 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationConfiguration.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.util.List; + +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.core.runtime.IAdaptable; + +import com.google.common.base.Preconditions; + +public class CompositeCreationConfiguration { + + private final Property compositeName; + private final Property> compositeProjects; + + public CompositeCreationConfiguration(Property compositeName, Property> compositeProjects) { + this.compositeName = Preconditions.checkNotNull(compositeName); + this.compositeProjects = Preconditions.checkNotNull(compositeProjects); + } + + public Property getCompositeName() { + return this.compositeName; + } + + public void setCompositeName(String compositeName) { + this.compositeName.setValue(compositeName); + } + + public Property> getCompositeProjects() { + return this.compositeProjects; + } + + public void setCompositeProjects(List compositeProjects) { + this.compositeProjects.setValue(compositeProjects); + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationWizardController.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationWizardController.java new file mode 100644 index 0000000000..9bf52530f2 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeCreationWizardController.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.core.internal.util.binding.Validators; +import org.eclipse.buildship.core.internal.util.collections.CollectionsUtils; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.wizard.IWizard; + +import com.google.common.collect.ImmutableList; + +public class CompositeCreationWizardController { + + private static final String SETTINGS_KEY_COMPOSITE_NAME = "composite_name"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_COMPOSITE_PROJECTS = "composite_projects"; //$NON-NLS-1$ + + private final CompositeCreationConfiguration configuration; + + public CompositeCreationWizardController(IWizard compositeCreationWizard) { + // assemble configuration object that serves as the data model of the wizard + Property compositeNameProperty = Property.create(Validators.uniqueWorkspaceCompositeNameValidator(WorkspaceCompositeWizardMessages.Label_CompositeName)); + Property> compositeProjectsProperty = Property.create(Validators.>nullValidator()); + + this.configuration = new CompositeCreationConfiguration(compositeNameProperty, compositeProjectsProperty); + + IDialogSettings dialogSettings = compositeCreationWizard.getDialogSettings(); + String compositeName = dialogSettings.get(SETTINGS_KEY_COMPOSITE_NAME); + List compositeProjects = ImmutableList.copyOf(getProjects(CollectionsUtils.nullToEmpty(dialogSettings.getArray(SETTINGS_KEY_COMPOSITE_PROJECTS)))); + + this.configuration.setCompositeName(compositeName); + this.configuration.setCompositeProjects(compositeProjects); + } + + public CompositeCreationWizardController(String compositeName, List compositeProjects) { + // assemble configuration object that serves as the data model of the wizard + Property compositeNameProperty = Property.create(Validators.uniqueWorkspaceCompositeNameValidator(WorkspaceCompositeWizardMessages.Label_CompositeName)); + Property> compositeProjectsProperty = Property.create(Validators.>nullValidator()); + + this.configuration = new CompositeCreationConfiguration(compositeNameProperty, compositeProjectsProperty); + + this.configuration.setCompositeName(compositeName); + this.configuration.setCompositeProjects(compositeProjects); + } + + private List getProjects(String[] projectArray) { + List projects = new ArrayList<>(); + for (String projectName : projectArray) { + projects.add(ResourcesPlugin.getWorkspace().getRoot().getProject(projectName)); + } + return projects; + } + + + public CompositeCreationConfiguration getConfiguration() { + return this.configuration; + } +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeImportWizardController.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeImportWizardController.java new file mode 100644 index 0000000000..816cb2e00a --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeImportWizardController.java @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.eclipse.buildship.core.GradleDistribution; +import org.eclipse.buildship.core.internal.i18n.CoreMessages; +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.core.internal.util.binding.ValidationListener; +import org.eclipse.buildship.core.internal.util.binding.Validator; +import org.eclipse.buildship.core.internal.util.binding.Validators; +import org.eclipse.buildship.core.internal.util.collections.CollectionsUtils; +import org.eclipse.buildship.core.internal.util.file.FileUtils; +import org.eclipse.buildship.ui.internal.UiPlugin; +import org.eclipse.buildship.ui.internal.util.gradle.GradleDistributionViewModel; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.wizard.IWizard; +import org.eclipse.jface.wizard.IWizardContainer; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +/** + * Controller class for the {@link WorkspaceCompositeCreationWizard}. Contains all non-UI related calculations + * the wizard has to perform. + */ +public class CompositeImportWizardController { + + private static String PROJECT_CREATION_DIALOG_SETTINGS = "org.eclipse.buildship.ui.wizard.composite.creation"; + + private IWorkingSet workingSet; + + // keys to load/store project properties in the dialog setting + private static final String SETTINGS_KEY_COMPOSITE_DIR = "composite_location"; //$NON-NLS-1$ + //private static final String SETTINGS_KEY_GRADLE_PROJECT_LIST = "gradle_project_list"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_GRADLE_DISTRIBUTION = "gradle_distribution"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_APPLY_WORKING_SETS = "apply_working_sets"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_WORKING_SETS = "working_sets"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_GRADLE_USER_HOME = "gradle_user_home"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_JAVA_HOME = "java_home"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_BUILD_SCANS = "build_scans"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_OFFLINE_MODE = "offline_mode"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_AUTO_SYNC = "auto_sync"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_ARGUMENTS = "arguments"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_JVM_ARGUMENTS = "jvm_arguments"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_SHOW_CONSOLE_VIEW = "show_console_view"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_SHOW_EXECUTIONS_VIEW = "show_executions_view"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_PROJECT_AS_COMPOSITE_ROOT = "project_as_composite_root"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_ROOT_PROJECT = "root_project"; //$NON-NLS-1$ + + private final CompositeConfiguration configuration; + + public CompositeImportWizardController(IWizard compositeImportWizard) { + // assemble configuration object that serves as the data model of the wizard + Validator compositePreferenceDirValidator = Validators.and( + Validators.requiredDirectoryValidator(WorkspaceCompositeWizardMessages.Label_CompositeName), + Validators.nonWorkspaceFolderValidator(WorkspaceCompositeWizardMessages.Label_CompositeName)); + Validator gradleDistributionValidator = GradleDistributionViewModel.validator(); + Validator applyWorkingSetsValidator = Validators.nullValidator(); + Validator> workingSetsValidator = Validators.nullValidator(); + Validator gradleUserHomeValidator = Validators.optionalDirectoryValidator(CoreMessages.Preference_Label_Gradle_User_Home); + Validator javaHomeValidator = Validators.optionalDirectoryValidator(CoreMessages.Preference_Label_Java_Home); + Validator rootProjectValidator = Validators.optionalDirectoryValidator(CoreMessages.Preference_Label_Root_Project); + + this.configuration = new CompositeConfiguration(compositePreferenceDirValidator, gradleDistributionValidator, gradleUserHomeValidator, javaHomeValidator, applyWorkingSetsValidator, workingSetsValidator, rootProjectValidator); + + // initialize values from the persisted dialog settings + IDialogSettings dialogSettings; + + if (compositeImportWizard != null) { + dialogSettings = compositeImportWizard.getDialogSettings(); + } else { + + dialogSettings = getOrCreateDialogSection(UiPlugin.getInstance().getDialogSettings()); + } + + Optional projectDir = FileUtils.getAbsoluteFile(dialogSettings.get(SETTINGS_KEY_COMPOSITE_DIR)); + String gradleDistributionString = dialogSettings.get(SETTINGS_KEY_GRADLE_DISTRIBUTION); + Optional gradleUserHome = FileUtils.getAbsoluteFile(dialogSettings.get(SETTINGS_KEY_GRADLE_USER_HOME)); + Optional javaHome = FileUtils.getAbsoluteFile(dialogSettings.get(SETTINGS_KEY_JAVA_HOME)); + boolean applyWorkingSets = dialogSettings.get(SETTINGS_KEY_APPLY_WORKING_SETS) != null && dialogSettings.getBoolean(SETTINGS_KEY_APPLY_WORKING_SETS); + List workingSets = ImmutableList.copyOf(CollectionsUtils.nullToEmpty(dialogSettings.getArray(SETTINGS_KEY_WORKING_SETS))); + boolean buildScansEnabled = dialogSettings.getBoolean(SETTINGS_KEY_BUILD_SCANS); + boolean offlineMode = dialogSettings.getBoolean(SETTINGS_KEY_OFFLINE_MODE); + boolean autoSync = dialogSettings.getBoolean(SETTINGS_KEY_AUTO_SYNC); + List arguments = ImmutableList.copyOf(CollectionsUtils.nullToEmpty(dialogSettings.getArray(SETTINGS_KEY_ARGUMENTS))); + List jvmArguments = ImmutableList.copyOf(CollectionsUtils.nullToEmpty(dialogSettings.getArray(SETTINGS_KEY_JVM_ARGUMENTS))); + boolean showConsoleView = dialogSettings.getBoolean(SETTINGS_KEY_SHOW_CONSOLE_VIEW); + boolean showExecutionsView = dialogSettings.getBoolean(SETTINGS_KEY_SHOW_EXECUTIONS_VIEW); + boolean projectAsCompositeRoot = dialogSettings.getBoolean(SETTINGS_KEY_PROJECT_AS_COMPOSITE_ROOT); + Optional rootProject = FileUtils.getAbsoluteFile(dialogSettings.get(SETTINGS_KEY_ROOT_PROJECT)); + + this.configuration.setCompositePreferencesDir(projectDir.orNull()); + this.configuration.setOverwriteWorkspaceSettings(false); + GradleDistribution distribution; + try { + distribution = GradleDistribution.fromString(gradleDistributionString); + } catch (RuntimeException ignore) { + distribution = GradleDistribution.fromBuild(); + } + this.configuration.setDistribution(GradleDistributionViewModel.from(distribution)); + this.configuration.setGradleUserHome(gradleUserHome.orNull()); + this.configuration.setJavaHomeHome(javaHome.orNull()); + this.configuration.setApplyWorkingSets(applyWorkingSets); + this.configuration.setWorkingSets(workingSets); + this.configuration.setBuildScansEnabled(buildScansEnabled); + this.configuration.setOfflineMode(offlineMode); + this.configuration.setAutoSync(autoSync); + this.configuration.setArguments(arguments); + this.configuration.setJvmArguments(jvmArguments); + this.configuration.setShowConsoleView(showConsoleView); + this.configuration.setShowExecutionsView(showExecutionsView); + this.configuration.setProjectAsCompositeRoot(projectAsCompositeRoot); + this.configuration.setRootProject(rootProject.orNull()); + + // store the values every time they change + saveFilePropertyWhenChanged(dialogSettings, SETTINGS_KEY_COMPOSITE_DIR, this.configuration.getCompositePreferencesDir()); + saveDistributionPropertyWhenChanged(dialogSettings, this.configuration.getDistribution()); + saveFilePropertyWhenChanged(dialogSettings, SETTINGS_KEY_GRADLE_USER_HOME, this.configuration.getGradleUserHome()); + saveFilePropertyWhenChanged(dialogSettings, SETTINGS_KEY_JAVA_HOME, this.configuration.getJavaHome()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_APPLY_WORKING_SETS, this.configuration.getApplyWorkingSets()); + saveStringArrayPropertyWhenChanged(dialogSettings, SETTINGS_KEY_WORKING_SETS, this.configuration.getWorkingSets()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_BUILD_SCANS, this.configuration.getBuildScansEnabled()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_OFFLINE_MODE, this.configuration.getOfflineMode()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_AUTO_SYNC, this.configuration.getAutoSync()); + saveStringArrayPropertyWhenChanged(dialogSettings, SETTINGS_KEY_ARGUMENTS, this.configuration.getArguments()); + saveStringArrayPropertyWhenChanged(dialogSettings, SETTINGS_KEY_JVM_ARGUMENTS, this.configuration.getJvmArguments()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_SHOW_CONSOLE_VIEW, this.configuration.getShowConsoleView()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_SHOW_EXECUTIONS_VIEW, this.configuration.getShowExecutionsView()); + saveBooleanPropertyWhenChanged(dialogSettings, SETTINGS_KEY_PROJECT_AS_COMPOSITE_ROOT, this.configuration.getProjectAsCompositeRoot()); + saveFilePropertyWhenChanged(dialogSettings, SETTINGS_KEY_ROOT_PROJECT, this.configuration.getRootProject()); + } + + private void saveBooleanPropertyWhenChanged(final IDialogSettings settings, final String settingsKey, final Property target) { + target.addValidationListener(new ValidationListener() { + + @Override + public void validationTriggered(Property source, Optional validationErrorMessage) { + settings.put(settingsKey, target.getValue()); + } + }); + } + + private void saveStringArrayPropertyWhenChanged(final IDialogSettings settings, final String settingsKey, final Property> target) { + target.addValidationListener(new ValidationListener() { + + @Override + public void validationTriggered(Property source, Optional validationErrorMessage) { + List value = target.getValue(); + settings.put(settingsKey, value.toArray(new String[value.size()])); + } + }); + } + + private void saveFilePropertyWhenChanged(final IDialogSettings settings, final String settingsKey, final Property target) { + target.addValidationListener(new ValidationListener() { + + @Override + public void validationTriggered(Property source, Optional validationErrorMessage) { + settings.put(settingsKey, FileUtils.getAbsolutePath(target.getValue()).orNull()); + } + }); + } + + private void saveDistributionPropertyWhenChanged(final IDialogSettings settings, final Property target) { + target.addValidationListener(new ValidationListener() { + + @Override + public void validationTriggered(Property source, Optional validationErrorMessage) { + if (!validationErrorMessage.isPresent()) { + settings.put(SETTINGS_KEY_GRADLE_DISTRIBUTION, target.getValue().toGradleDistribution().toString()); + } else { + settings.put(SETTINGS_KEY_GRADLE_DISTRIBUTION, GradleDistribution.fromBuild().toString()); + } + } + }); + } + + public CompositeConfiguration getConfiguration() { + return this.configuration; + } + + public boolean performCreateComposite(IWizardContainer container, IWorkingSetManager workingSetManager) { + try { + File compositePreferenceFile = this.configuration.getCompositePreferencesDir().getValue(); + List projects = new ArrayList<>(); + for (IAdaptable project : getConfiguration().getProjectList().getValue()) { + projects.add((IProject) project); + } + this.workingSet = workingSetManager.createWorkingSet(compositePreferenceFile.getName(), projects.toArray(new IProject[projects.size()])); + this.workingSet.setId(IGradleCompositeIDs.NATURE); + workingSetManager.addWorkingSet(this.workingSet); + + compositePreferenceFile.getParentFile().mkdir(); + compositePreferenceFile.createNewFile(); + FileOutputStream out = new FileOutputStream(compositePreferenceFile.getAbsoluteFile()); + Properties prop = getConfiguration().toCompositeProperties().toProperties(); + prop.store(out, " "); + out.close(); + } catch (IOException e) { + e.printStackTrace(); + } + return true; + } + + private static IDialogSettings getOrCreateDialogSection(IDialogSettings dialogSettings) { + IDialogSettings section = dialogSettings.getSection(PROJECT_CREATION_DIALOG_SETTINGS); + if (section == null) { + section = dialogSettings.addNewSection(PROJECT_CREATION_DIALOG_SETTINGS); + } + return section; + } + + public IWorkingSet getWorkingSet() { + return this.workingSet; + } +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectConfiguration.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectConfiguration.java new file mode 100644 index 0000000000..bfba41f604 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectConfiguration.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.io.File; + +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.core.internal.util.binding.Validators; + +import com.google.common.base.Preconditions; + +public class CompositeRootProjectConfiguration { + + private final Property useCompositeRoot; + private final Property rootProject; + + public CompositeRootProjectConfiguration(){ + this(Property.create(Validators.noOp()), Property.create(Validators.noOp())); + } + + public CompositeRootProjectConfiguration(Property useCompositeRoot, Property rootProject) { + this.useCompositeRoot = Preconditions.checkNotNull(useCompositeRoot); + this.rootProject = Preconditions.checkNotNull(rootProject); + } + + public Property getUseCompositeRoot() { + return this.useCompositeRoot; + } + + public void setUseCompositeRoot(Boolean useCompositeRoot) { + this.useCompositeRoot.setValue(useCompositeRoot); + } + + public Property getRootProject() { + return this.rootProject; + } + + public void setRootProject(File rootProject) { + this.rootProject.setValue(rootProject); + } + + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectWizardController.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectWizardController.java new file mode 100644 index 0000000000..b30f302052 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/CompositeRootProjectWizardController.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.io.File; + +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.core.internal.util.binding.Validators; +import org.eclipse.buildship.core.internal.util.file.FileUtils; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.wizard.IWizard; + +import com.google.common.base.Optional; + +public class CompositeRootProjectWizardController { + + private static final String SETTINGS_KEY_USE_COMPOSITE_ROOT = "use_composite_root"; //$NON-NLS-1$ + private static final String SETTINGS_KEY_COMPOSITE_ROOT_PROJECT = "composite_root_project"; //$NON-NLS-1$ + + private final CompositeRootProjectConfiguration configuration; + + public CompositeRootProjectWizardController(IWizard compositeCreationWizard) { + // assemble configuration object that serves as the data model of the wizard + Property compositeNameProperty = Property.create(Validators.nullValidator()); + Property compositeProjectsProperty = Property.create(Validators.nonExistentDirectoryValidator(WorkspaceCompositeWizardMessages.Label_RootProject)); + + this.configuration = new CompositeRootProjectConfiguration(compositeNameProperty, compositeProjectsProperty); + + IDialogSettings dialogSettings = compositeCreationWizard.getDialogSettings(); + Boolean useCompositeRoot = dialogSettings.getBoolean(SETTINGS_KEY_USE_COMPOSITE_ROOT); + Optional compositeRootProject = FileUtils.getAbsoluteFile(dialogSettings.get(SETTINGS_KEY_COMPOSITE_ROOT_PROJECT)); + + this.configuration.setUseCompositeRoot(useCompositeRoot); + this.configuration.setRootProject(compositeRootProject.orNull()); + } + + public CompositeRootProjectConfiguration getConfiguration() { + return this.configuration; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProject.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProject.java new file mode 100644 index 0000000000..e635e97ddd --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProject.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +public class ExternalGradleProject { + //TODO (kuzniarz) initial implementation needs to be finished + + private String projectName; + private String projectPath; + + public ExternalGradleProject(String name, String path) { + this.projectName = name; + this.projectPath = path; + } + + public String getProjectName() { + return this.projectName; + } + + public String getProjectPath() { + return this.projectPath; + } +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProjectAdapter.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProjectAdapter.java new file mode 100644 index 0000000000..05aeb109c6 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalGradleProjectAdapter.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +public class ExternalGradleProjectAdapter { + + private final ExternalGradleProject gradleProject; + + public ExternalGradleProjectAdapter(ExternalGradleProject project) { + this.gradleProject = project; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalProjectAdapterFactory.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalProjectAdapterFactory.java new file mode 100644 index 0000000000..8b779da96c --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/ExternalProjectAdapterFactory.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import org.eclipse.core.runtime.IAdapterFactory; + +public class ExternalProjectAdapterFactory implements IAdapterFactory { + + @Override + public Object getAdapter(Object adaptableObject, Class adapterType) { + if (adaptableObject instanceof ExternalGradleProject){ + return new ExternalGradleProjectAdapter((ExternalGradleProject) adaptableObject); + } + return null; + } + + @Override + public Class[] getAdapterList() { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleCreateWorkspaceCompositeWizardPage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleCreateWorkspaceCompositeWizardPage.java index a95e79b247..875005fd77 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleCreateWorkspaceCompositeWizardPage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleCreateWorkspaceCompositeWizardPage.java @@ -10,34 +10,87 @@ package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; + +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Text; +import org.eclipse.swt.widgets.TreeItem; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.PlatformUI; +import org.eclipse.buildship.core.internal.CorePlugin; +import org.eclipse.buildship.core.internal.util.binding.Property; import org.eclipse.buildship.ui.internal.util.layout.LayoutUtils; import org.eclipse.buildship.ui.internal.util.widget.GradleProjectGroup; /** * Page on the {@link WorkspaceCompositeCreationWizard} declaring the workspace composite name and included projects. */ -public final class GradleCreateWorkspaceCompositeWizardPage extends AbstractWizardPage { +public final class GradleCreateWorkspaceCompositeWizardPage extends AbstractCompositeWizardPage { + + private final CompositeCreationConfiguration creationConfiguration; + @SuppressWarnings("unused") private Text workspaceCompositeNameText; private Label compositeName; private GradleProjectGroup gradleProjectCheckboxtreeComposite; + private static IWorkingSet gradleComposite; + private boolean firstCheck; + + public GradleCreateWorkspaceCompositeWizardPage(CompositeConfiguration importConfiguration, CompositeCreationConfiguration creationConfiguration) { + super("NewGradleWorkspaceComposite", WorkspaceCompositeWizardMessages.Title_NewGradleWorkspaceCompositeWizardPage, WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault, //$NON-NLS-1$ + importConfiguration, ImmutableList.of(creationConfiguration.getCompositeName(), creationConfiguration.getCompositeProjects())); + + this.creationConfiguration = creationConfiguration; + this.firstCheck = true; + } + public GradleCreateWorkspaceCompositeWizardPage() { - super("NewGradleWorkspaceComposite", WorkspaceCompositeWizardMessages.Title_NewGradleWorkspaceCompositeWizardPage, WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault); //$NON-NLS-1$ + this(getCompositeImportConfiguration(), getCompositeCreationConfiguration()); + } + + + private static CompositeCreationConfiguration getCompositeCreationConfiguration() { + CompositeCreationWizardController creationController; + ArrayList compositeElements = new ArrayList<>(); + if (gradleComposite != null) { + creationController = new CompositeCreationWizardController(gradleComposite.getName(), compositeElements); + } else { + creationController = new CompositeCreationWizardController("", compositeElements); + } + return creationController.getConfiguration(); + } + + private static CompositeConfiguration getCompositeImportConfiguration() { + return new CompositeConfiguration(); + } + + protected String getPageId() { + return "org.eclipse.buildship.ui.GradleCompositePage"; //$NON-NLS-1$ } @Override protected void createWidgets(Composite root) { root.setLayout(LayoutUtils.newGridLayout(3)); createContent(root); + bindToConfiguration(); } private void createContent(Composite root) { @@ -56,9 +109,60 @@ private void createContent(Composite root) { this.workspaceCompositeNameText = new Text(workspaceCompositeNameComposite, SWT.BORDER); this.workspaceCompositeNameText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); - this.gradleProjectCheckboxtreeComposite = new GradleProjectGroup(root); + this.gradleProjectCheckboxtreeComposite = new GradleProjectGroup(root, hasSelectedElement()); GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).span(3, SWT.DEFAULT).applyTo(this.gradleProjectCheckboxtreeComposite); + getConfiguration().getProjectList().setValue(new IAdaptable[0]); + + if (gradleComposite != null) { + this.workspaceCompositeNameText.setText(gradleComposite.getName()); + } + } + + private void bindToConfiguration() { + this.workspaceCompositeNameText.addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + updateLocation(); + } + }); + this.gradleProjectCheckboxtreeComposite.getCheckboxTree().addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event event) { + updateCompositeProjects(); + } + }); + } + + private void updateLocation() { + File parentLocation = CorePlugin.getInstance().getStateLocation().append("workspace-composites").toFile(); + File projectDir = parentLocation != null ? new File(parentLocation, this.workspaceCompositeNameText.getText()) : null; + + // always update project name last to ensure project name validation errors have precedence in the UI + getConfiguration().getCompositePreferencesDir().setValue(projectDir); + this.creationConfiguration.setCompositeName(this.workspaceCompositeNameText.getText()); + } + + protected void updateCompositeProjects() { + List projectList = new ArrayList<>(); + + for (TreeItem treeElement : this.gradleProjectCheckboxtreeComposite.getCheckboxTree().getItems()) { + if (treeElement.getChecked() == true) { + if (treeElement.getText().contains(" (External): ")) { + //String[] treeValues = treeElement.getText().replace(" (External): ", "$").split("\\$"); + // treeValues[0] contains the project name + // treeValues[1] contains the file path + //File externalFolder = new File(treeValues[1]); + projectList.add(null); + } else { + projectList.add(ResourcesPlugin.getWorkspace().getRoot().getProject(treeElement.getText())); + } + } + } + getConfiguration().getProjectList().setValue(projectList.toArray(new IAdaptable[projectList.size()])); + this.creationConfiguration.setCompositeProjects(projectList); } @Override @@ -66,4 +170,53 @@ protected String getPageContextInformation() { return WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeWizardPageContext; } + /* + * Has to be implemented here because of gradleComposite checks to prevent "name exists" bug while editing + */ + @Override + protected void validateInput(Property source, Optional validationErrorMessage) { + String errorMessage = null; + String infoMessage = null; + String newText= this.workspaceCompositeNameText.getText(); + + if (newText.equals(newText.trim()) == false) { + errorMessage = WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_NameWhitespaces; + } + if (newText.isEmpty()) { + if (this.firstCheck) { + setPageComplete(false); + this.firstCheck= false; + return; + } else { + errorMessage = WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_NameEmpty; + } + } + + this.firstCheck= false; + + if (errorMessage == null && (gradleComposite == null || newText.equals(gradleComposite.getName()) == false)) { + IWorkingSet[] workingSets= PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets(); + for (int i= 0; i < workingSets.length; i++) { + if (newText.equals(workingSets[i].getName())) { + errorMessage= WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_CompositeNameExists; + } + } + } + + if (!hasSelectedElement()) { + infoMessage = WorkspaceCompositeWizardMessages.WarningMessage_GradleWorkspaceComposite_CompositeEmpty; + setMessage(infoMessage, INFORMATION); + } else { + setMessage(WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault); + } + + + setErrorMessage(errorMessage); + setPageComplete(errorMessage == null); + } + + private boolean hasSelectedElement() { + return this.creationConfiguration.getCompositeProjects().getValue().size() > 0; + } + } diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleImportOptionsWizardPage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleImportOptionsWizardPage.java index 0ff1207239..33cc8b229e 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleImportOptionsWizardPage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleImportOptionsWizardPage.java @@ -9,33 +9,43 @@ ******************************************************************************/ package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; +import com.google.common.collect.ImmutableList; + import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; +import org.eclipse.jface.wizard.IWizardPage; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.widgets.Composite; import org.eclipse.ui.dialogs.PreferencesUtil; +import org.eclipse.buildship.core.internal.util.binding.Property; import org.eclipse.buildship.ui.internal.preferences.GradleWorkbenchPreferencePage; +import org.eclipse.buildship.ui.internal.util.gradle.GradleDistributionViewModel; +import org.eclipse.buildship.ui.internal.util.widget.GradleDistributionGroup.DistributionChangedListener; import org.eclipse.buildship.ui.internal.util.widget.GradleProjectSettingsComposite; +import org.eclipse.buildship.ui.internal.util.widget.StringListEditor.StringListChangeListener; /** * Page on the {@link WorkspaceCompositeCreationWizard} declaring the used Gradle distribution and other advanced options for the composite projects. */ -public final class GradleImportOptionsWizardPage extends AbstractWizardPage { +public final class GradleImportOptionsWizardPage extends AbstractCompositeWizardPage { private final String pageContextInformation; private GradleProjectSettingsComposite gradleProjectSettingsComposite; - public GradleImportOptionsWizardPage() { - this(WorkspaceCompositeWizardMessages.Title_GradleImportOptionsWizardPage, WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeOptionsWizardPageDefault, + public GradleImportOptionsWizardPage(CompositeConfiguration configuration) { + this(configuration, WorkspaceCompositeWizardMessages.Title_GradleImportOptionsWizardPage, WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeOptionsWizardPageDefault, WorkspaceCompositeWizardMessages.InfoMessage_GradleImportOptionsWizardPageContext); } - public GradleImportOptionsWizardPage(String title, String defaultMessage, String pageContextInformation) { - super("GradleImportOptions", title, defaultMessage); + public GradleImportOptionsWizardPage(CompositeConfiguration configuration, String title, String defaultMessage, String pageContextInformation) { + super("GradleImportOptions", title, defaultMessage, configuration, ImmutableList.>of(configuration.getDistribution(), configuration.getGradleUserHome(), configuration.getJavaHome())); this.pageContextInformation = pageContextInformation; + } @Override @@ -48,6 +58,157 @@ protected void createWidgets(Composite root) { GridDataFactory.fillDefaults().grab(true, false).applyTo(this.gradleProjectSettingsComposite); this.gradleProjectSettingsComposite.getParentPreferenceLink().addSelectionListener(new WorkbenchPreferenceOpeningSelectionListener()); + + initValues(); + addListeners(); + } + + @Override + public IWizardPage getNextPage() { + IWizardPage page = new GradleRootProjectWizardPage(getConfiguration(), new CompositeRootProjectConfiguration()); + page.setWizard(getWizard()); + return page; + } + + private void initValues() { + this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().setSelection(getConfiguration().getOverrideWorkspaceConfiguration().getValue()); + this.gradleProjectSettingsComposite.getGradleDistributionGroup().setDistribution(getConfiguration().getDistribution().getValue()); + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setGradleUserHome(getConfiguration().getGradleUserHome().getValue()); + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setJavaHome(getConfiguration().getJavaHome().getValue()); + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setArguments(getConfiguration().getArguments().getValue()); + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setJvmArguments(getConfiguration().getJvmArguments().getValue()); + this.gradleProjectSettingsComposite.getBuildScansCheckbox().setSelection(getConfiguration().getBuildScansEnabled().getValue()); + this.gradleProjectSettingsComposite.getOfflineModeCheckbox().setSelection(getConfiguration().getOfflineMode().getValue()); + this.gradleProjectSettingsComposite.getAutoSyncCheckbox().setSelection(getConfiguration().getAutoSync().getValue()); + this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().setSelection(getConfiguration().getShowConsoleView().getValue()); + this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().setSelection(getConfiguration().getShowExecutionsView().getValue()); + this.gradleProjectSettingsComposite.updateEnablement(); + } + + private void addListeners() { + this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getOverrideWorkspaceConfiguration().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().getSelection()); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getOverrideWorkspaceConfiguration().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().getSelection()); + } + }); + + this.gradleProjectSettingsComposite.getGradleDistributionGroup().addDistributionChangedListener(new DistributionChangedListener() { + + @Override + public void distributionUpdated(GradleDistributionViewModel distribution) { + getConfiguration().setDistribution(distribution); + } + }); + + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getGradleUserHomeText().addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + getConfiguration().setGradleUserHome(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getGradleUserHome()); + } + }); + + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJavaHomeText().addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + getConfiguration().setJavaHomeHome(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJavaHome()); + } + }); + + + this.gradleProjectSettingsComposite.getBuildScansCheckbox().addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getBuildScansEnabled().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getBuildScansCheckbox().getSelection()); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getBuildScansEnabled().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getBuildScansCheckbox().getSelection()); + } + }); + + this.gradleProjectSettingsComposite.getOfflineModeCheckbox().addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getOfflineMode().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getOfflineModeCheckbox().getSelection()); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getOfflineMode().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getOfflineModeCheckbox().getSelection()); + } + }); + this.gradleProjectSettingsComposite.getAutoSyncCheckbox().addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getAutoSync().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getAutoSyncCheckbox().getSelection()); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getAutoSync().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getAutoSyncCheckbox().getSelection()); + } + }); + + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getArgumentsEditor().addChangeListener(new StringListChangeListener() { + + @Override + public void onChange() { + getConfiguration().getArguments().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getArguments()); + } + }); + + this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJvmArgumentsEditor().addChangeListener(new StringListChangeListener() { + + @Override + public void onChange() { + getConfiguration().getJvmArguments().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().getJvmArguments()); + } + }); + + this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getShowConsoleView().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().getSelection()); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getShowConsoleView().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().getSelection()); + } + }); + + this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getShowExecutionsView().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().getSelection()); + + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getShowExecutionsView().setValue(GradleImportOptionsWizardPage.this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().getSelection()); + } + }); + } @Override diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleRootProjectWizardPage.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleRootProjectWizardPage.java index a709b48ffc..54cdc0e37e 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleRootProjectWizardPage.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleRootProjectWizardPage.java @@ -10,10 +10,17 @@ package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; -import org.eclipse.buildship.ui.internal.util.layout.LayoutUtils; +import java.io.File; + +import com.google.common.collect.ImmutableList; + import org.eclipse.jface.layout.GridDataFactory; import org.eclipse.jface.layout.GridLayoutFactory; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; @@ -22,33 +29,47 @@ import org.eclipse.swt.widgets.Layout; import org.eclipse.swt.widgets.Text; +import org.eclipse.buildship.core.internal.util.binding.Property; +import org.eclipse.buildship.ui.internal.util.file.DirectoryDialogSelectionListener; +import org.eclipse.buildship.ui.internal.util.layout.LayoutUtils; + /** * Page in the {@link WorkspaceCompositeCreationWizard} for setting a project as composite root. */ @SuppressWarnings("unused") -public final class GradleRootProjectWizardPage extends AbstractWizardPage { +public final class GradleRootProjectWizardPage extends AbstractCompositeWizardPage { + + private final CompositeRootProjectConfiguration rootProjectConfiguration; - private Text workspaceCompositeRootProjectLabel; - private Text overrideCheckboxLabel; - private Button overrideSettingsCheckbox; + private Text workspaceCompositeRootProjectText; + private Text overrideRootProjectCheckboxLabel; + private Button overrideRootProjectCheckbox; private Button selectRootProject; private Label rootProjectLabel; - public GradleRootProjectWizardPage() { + public GradleRootProjectWizardPage(CompositeConfiguration configuration, CompositeRootProjectConfiguration rootProjectConfiguration) { this(WorkspaceCompositeWizardMessages.Title_CompositeRootWizardPage, WorkspaceCompositeWizardMessages.InfoMessage_CompositeRootWizardPageDefault, - WorkspaceCompositeWizardMessages.InfoMessage_CompositeRootWizardPageContext); + WorkspaceCompositeWizardMessages.InfoMessage_CompositeRootWizardPageContext, configuration, rootProjectConfiguration); } public GradleRootProjectWizardPage(String title, String defaultMessage, - String pageContextInformation) { - super("CompositeRootProject", title, defaultMessage); //$NON-NLS-1$ + String pageContextInformation, CompositeConfiguration configuration, CompositeRootProjectConfiguration rootProjectConfiguration) { + super("CompositeRootProject", title, defaultMessage, configuration, ImmutableList.>of(rootProjectConfiguration.getUseCompositeRoot(), rootProjectConfiguration.getRootProject())); //$NON-NLS-1$ + + this.rootProjectConfiguration = rootProjectConfiguration; } @Override protected void createWidgets(Composite root) { root.setLayout(createLayout()); createContent(root); + addListeners(); + } + + private void initValues() { + this.overrideRootProjectCheckbox.setSelection(this.rootProjectConfiguration.getUseCompositeRoot().getValue()); + this.workspaceCompositeRootProjectText.setText(this.rootProjectConfiguration.getRootProject().getValue().getAbsolutePath()); } private Layout createLayout() { @@ -60,8 +81,8 @@ private Layout createLayout() { private void createContent(Composite root) { - this.overrideSettingsCheckbox = new Button(root, SWT.CHECK); - this.overrideSettingsCheckbox.setText("Use project as composite root"); + this.overrideRootProjectCheckbox = new Button(root, SWT.CHECK); + this.overrideRootProjectCheckbox.setText("Use project as composite root"); GridDataFactory.swtDefaults().applyTo(root); Label line = new Label(root, SWT.SEPARATOR | SWT.HORIZONTAL); @@ -77,14 +98,63 @@ private void createContent(Composite root) { this.rootProjectLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1)); this.rootProjectLabel.setText(WorkspaceCompositeWizardMessages.Label_RootProject); + this.rootProjectLabel.setEnabled(false); + // root project text field - this.workspaceCompositeRootProjectLabel = new Text(workspaceCompositeNameComposite, SWT.BORDER); - this.workspaceCompositeRootProjectLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); + this.workspaceCompositeRootProjectText = new Text(workspaceCompositeNameComposite, SWT.BORDER); + this.workspaceCompositeRootProjectText.setEnabled(false); + this.workspaceCompositeRootProjectText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1)); // root project select button this.selectRootProject = new Button(workspaceCompositeNameComposite, SWT.PUSH); this.selectRootProject.setLayoutData(new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1)); + this.selectRootProject.setEnabled(false); this.selectRootProject.setText(WorkspaceCompositeWizardMessages.Button_Select_RootProject); + + } + + private File getRootProject() { + String rootProjectString = this.workspaceCompositeRootProjectText.getText(); + return rootProjectString.isEmpty() ? null : new File(rootProjectString); + } + + private void addListeners() { + if (this.overrideRootProjectCheckbox != null) { + this.overrideRootProjectCheckbox.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + getConfiguration().getProjectAsCompositeRoot().setValue(GradleRootProjectWizardPage.this.overrideRootProjectCheckbox.getSelection()); + updateEnablement(); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + getConfiguration().getProjectAsCompositeRoot().setValue(GradleRootProjectWizardPage.this.overrideRootProjectCheckbox.getSelection()); + updateEnablement(); + } + }); + + this.workspaceCompositeRootProjectText.addModifyListener(new ModifyListener() { + + @Override + public void modifyText(ModifyEvent e) { + getConfiguration().getRootProject().setValue(GradleRootProjectWizardPage.this.getRootProject()); + + } + }); + + this.selectRootProject.addSelectionListener(new DirectoryDialogSelectionListener(this.getShell(), this.workspaceCompositeRootProjectText, "Root project")); + } + } + + public void updateEnablement() { + if (this.overrideRootProjectCheckbox != null) { + boolean enabled = this.overrideRootProjectCheckbox.getSelection(); + this.rootProjectLabel.setEnabled(enabled); + this.workspaceCompositeRootProjectText.setEnabled(enabled); + this.selectRootProject.setEnabled(enabled); + } } @Override diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleWorkspaceCompositeUpdater.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleWorkspaceCompositeUpdater.java new file mode 100644 index 0000000000..768f584c8c --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/GradleWorkspaceCompositeUpdater.java @@ -0,0 +1,238 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.resources.IResourceDelta; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jdt.core.ElementChangedEvent; +import org.eclipse.jdt.core.IElementChangedListener; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IJavaElementDelta; +import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.internal.ui.workingsets.IWorkingSetIDs; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetUpdater; + + +public class GradleWorkspaceCompositeUpdater implements IWorkingSetUpdater, IElementChangedListener { + + /** + * DO NOT REMOVE, used in a product, see https://bugs.eclipse.org/297529 . + * @deprecated As of 3.5, replaced by {@link IWorkingSetIDs#JAVA} + */ + @Deprecated + public static final String ID= "org.eclipse.buildship.core.gradlecompositenature"; + + + private List fWorkingSets; + + private static class WorkingSetDelta { + private IWorkingSet fWorkingSet; + private List fElements; + private boolean fChanged; + public WorkingSetDelta(IWorkingSet workingSet) { + this.fWorkingSet= workingSet; + this.fElements= new ArrayList<>(Arrays.asList(workingSet.getElements())); + } + public int indexOf(Object element) { + return this.fElements.indexOf(element); + } + public void set(int index, IAdaptable element) { + this.fElements.set(index, element); + this.fChanged= true; + } + public void remove(int index) { + if (this.fElements.remove(index) != null) { + this.fChanged= true; + } + } + public void process() { + if (this.fChanged) { + this.fWorkingSet.setElements(this.fElements.toArray(new IAdaptable[this.fElements.size()])); + } + } + } + + public GradleWorkspaceCompositeUpdater() { + this.fWorkingSets= new ArrayList<>(); + } + + @Override + public void add(IWorkingSet workingSet) { + checkElementExistence(workingSet); + synchronized (this.fWorkingSets) { + this.fWorkingSets.add(workingSet); + } + } + + @Override + public boolean remove(IWorkingSet workingSet) { + boolean result; + synchronized(this.fWorkingSets) { + result= this.fWorkingSets.remove(workingSet); + } + return result; + } + + @Override + public boolean contains(IWorkingSet workingSet) { + synchronized(this.fWorkingSets) { + return this.fWorkingSets.contains(workingSet); + } + } + + @Override + public void dispose() { + synchronized(this.fWorkingSets) { + this.fWorkingSets.clear(); + } + } + + @Override + public void elementChanged(ElementChangedEvent event) { + IWorkingSet[] workingSets; + synchronized(this.fWorkingSets) { + workingSets= this.fWorkingSets.toArray(new IWorkingSet[this.fWorkingSets.size()]); + } + for (int w= 0; w < workingSets.length; w++) { + WorkingSetDelta workingSetDelta= new WorkingSetDelta(workingSets[w]); + processJavaDelta(workingSetDelta, event.getDelta()); + IResourceDelta[] resourceDeltas= event.getDelta().getResourceDeltas(); + if (resourceDeltas != null) { + for (int r= 0; r < resourceDeltas.length; r++) { + processResourceDelta(workingSetDelta, resourceDeltas[r]); + } + } + workingSetDelta.process(); + } + } + + private void processJavaDelta(WorkingSetDelta result, IJavaElementDelta delta) { + IJavaElement jElement= delta.getElement(); + int index= result.indexOf(jElement); + int type= jElement.getElementType(); + int kind= delta.getKind(); + int flags= delta.getFlags(); + if (type == IJavaElement.JAVA_PROJECT && kind == IJavaElementDelta.CHANGED) { + if (index != -1 && (flags & IJavaElementDelta.F_CLOSED) != 0) { + result.set(index, ((IJavaProject)jElement).getProject()); + } else if ((flags & IJavaElementDelta.F_OPENED) != 0) { + index= result.indexOf(((IJavaProject)jElement).getProject()); + if (index != -1) { + result.set(index, jElement); + } + } + } + if (index != -1) { + if (kind == IJavaElementDelta.REMOVED) { + if ((flags & IJavaElementDelta.F_MOVED_TO) != 0) { + result.set(index, delta.getMovedToElement()); + } else { + result.remove(index); + } + } + } + IResourceDelta[] resourceDeltas= delta.getResourceDeltas(); + if (resourceDeltas != null) { + for (int i= 0; i < resourceDeltas.length; i++) { + processResourceDelta(result, resourceDeltas[i]); + } + } + IJavaElementDelta[] children= delta.getAffectedChildren(); + for (int i= 0; i < children.length; i++) { + processJavaDelta(result, children[i]); + } + } + + private void processResourceDelta(WorkingSetDelta result, IResourceDelta delta) { + IResource resource= delta.getResource(); + int type= resource.getType(); + int index= result.indexOf(resource); + int kind= delta.getKind(); + int flags= delta.getFlags(); + if (kind == IResourceDelta.CHANGED && type == IResource.PROJECT && index != -1) { + if ((flags & IResourceDelta.OPEN) != 0) { + result.set(index, resource); + } + } + if (index != -1 && kind == IResourceDelta.REMOVED) { + if ((flags & IResourceDelta.MOVED_TO) != 0) { + result.set(index, + ResourcesPlugin.getWorkspace().getRoot().findMember(delta.getMovedToPath())); + } else { + result.remove(index); + } + } + + // Don't dive into closed or opened projects + if (projectGotClosedOrOpened(resource, kind, flags)) { + return; + } + + IResourceDelta[] children= delta.getAffectedChildren(); + for (int i= 0; i < children.length; i++) { + processResourceDelta(result, children[i]); + } + } + + private boolean projectGotClosedOrOpened(IResource resource, int kind, int flags) { + return resource.getType() == IResource.PROJECT + && kind == IResourceDelta.CHANGED + && (flags & IResourceDelta.OPEN) != 0; + } + + private void checkElementExistence(IWorkingSet workingSet) { + List elements= new ArrayList<>(Arrays.asList(workingSet.getElements())); + boolean changed= false; + for (Iterator iter= elements.iterator(); iter.hasNext();) { + IAdaptable element= iter.next(); + boolean remove= false; + if (element instanceof IJavaElement) { + IJavaElement jElement= (IJavaElement)element; + // If we have directly a project then remove it when it + // doesn't exist anymore. However if we have a sub element + // under a project only remove the element if the parent + // project is open. Otherwise we would remove all elements + // in closed projects. + if (jElement instanceof IJavaProject) { + remove= !jElement.exists(); + } else { + final IJavaProject javaProject= jElement.getJavaProject(); + final boolean isProjectOpen= javaProject != null ? javaProject.getProject().isOpen() : true; + remove= isProjectOpen && !jElement.exists(); + } + } else if (element instanceof IResource) { + IResource resource= (IResource)element; + // See comments above + if (resource instanceof IProject) { + remove= !resource.exists(); + } else { + IProject project= resource.getProject(); + remove= (project != null ? project.isOpen() : true) && !resource.exists(); + } + } + if (remove) { + iter.remove(); + changed= true; + } + } + if (changed) { + workingSet.setElements(elements.toArray(new IAdaptable[elements.size()])); + } + } +} \ No newline at end of file diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/IGradleCompositeIDs.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/IGradleCompositeIDs.java new file mode 100644 index 0000000000..fa12eb509c --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/IGradleCompositeIDs.java @@ -0,0 +1,23 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; + +/** + * + * @author Sebastian Kuzniarz (kuzniarz) - Diebold Nixdorf Inc. + * + */ + +public interface IGradleCompositeIDs { + + String NATURE = "org.eclipse.buildship.ui.GradleCompositePage"; + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeCreationWizard.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeCreationWizard.java index 641a4c9675..c83e931f2c 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeCreationWizard.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeCreationWizard.java @@ -9,12 +9,15 @@ ******************************************************************************/ package org.eclipse.buildship.ui.internal.wizard.workspacecomposite; -import org.eclipse.buildship.ui.internal.UiPlugin; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.wizard.IWizardContainer; import org.eclipse.ui.INewWizard; import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; + +import org.eclipse.buildship.ui.internal.UiPlugin; /** * Eclipse wizard for creating Gradle composites in the workspace. @@ -27,18 +30,22 @@ public final class WorkspaceCompositeCreationWizard extends AbstractWorkspaceCom * * @see org.eclipse.jface.dialogs.DialogSettings#getOrCreateSection(IDialogSettings, String) */ - private static final String PROJECT_CREATION_DIALOG_SETTINGS = "org.eclipse.buildship.ui.wizard.project.creation"; //$NON-NLS-1$ - - /** - * Preference key that flags whether the welcome page should be shown as part of the creation wizard. - */ - private static final String PREF_SHOW_WELCOME_PAGE = "org.eclipse.buildship.ui.wizard.project.creation.showWelcomePage"; //$NON-NLS-1$ + private static final String PROJECT_CREATION_DIALOG_SETTINGS = "org.eclipse.buildship.ui.wizard.composite.creation"; //$NON-NLS-1$ // the pages to display in the wizard private final GradleCreateWorkspaceCompositeWizardPage newGradleWorkspaceCompositePage; private final GradleImportOptionsWizardPage compositeImportOptionsPage; private final GradleRootProjectWizardPage compositeRootProjectPage; + // the controller that contain the wizard logic + private final CompositeImportWizardController importController; + private final CompositeCreationWizardController creationController; + private final CompositeRootProjectWizardController rootProjectController; + + // working set manager + private IWorkingSetManager workingSetManager; + + /** * Creates a new instance and uses the {@link org.eclipse.jface.dialogs.DialogSettings} from {@link org.eclipse.buildship.ui.internal.UiPlugin}.. */ @@ -52,23 +59,26 @@ public WorkspaceCompositeCreationWizard() { * @param dialogSettings the dialog settings to store/retrieve dialog preferences */ public WorkspaceCompositeCreationWizard(IDialogSettings dialogSettings) { - super(PREF_SHOW_WELCOME_PAGE); // store the dialog settings on the wizard and use them to retrieve / persist the most // recent values entered by the user setDialogSettings(dialogSettings); + this.workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager(); + + // instantiate the controllers for this wizard + this.importController = new CompositeImportWizardController(this); + this.creationController = new CompositeCreationWizardController(this); + this.rootProjectController = new CompositeRootProjectWizardController(this); + // instantiate the pages and pass the configuration objects that serve as // the data models of the wizard - this.newGradleWorkspaceCompositePage = new GradleCreateWorkspaceCompositeWizardPage(); - this.compositeImportOptionsPage = new GradleImportOptionsWizardPage( - WorkspaceCompositeWizardMessages.Title_NewGradleImportOptionsWizardPage, - WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeOptionsWizardPageDefault, - WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeImportOptionsWizardPageContext); - this.compositeRootProjectPage = new GradleRootProjectWizardPage( - WorkspaceCompositeWizardMessages.Title_NewGradleCompositeRootWizardPage, - WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositePreviewWizardPageDefault, - WorkspaceCompositeWizardMessages.InfoMessage_NewGradleWorkspaceCompositeCompositeRootWizardPageContext); + final CompositeConfiguration compositeConfiguration = this.importController.getConfiguration(); + final CompositeCreationConfiguration creationConfiguration = this.creationController.getConfiguration(); + final CompositeRootProjectConfiguration rootProjectConfiguration = this.rootProjectController.getConfiguration(); + this.newGradleWorkspaceCompositePage = new GradleCreateWorkspaceCompositeWizardPage(compositeConfiguration, creationConfiguration); + this.compositeImportOptionsPage = new GradleImportOptionsWizardPage(compositeConfiguration); + this.compositeRootProjectPage = new GradleRootProjectWizardPage(compositeConfiguration, rootProjectConfiguration); } @Override @@ -98,7 +108,7 @@ public void addPages() { @Override public boolean performFinish() { - return false; + return this.importController.performCreateComposite(getContainer(), this.workingSetManager); } @Override diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.java index 47024e2a61..d0e3b9413f 100644 --- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.java +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.java @@ -30,6 +30,11 @@ public final class WorkspaceCompositeWizardMessages extends NLS { public static String InfoMessage_CompositeRootWizardPageDefault; + public static String WarningMessage_GradleWorkspaceComposite_NameWhitespaces; + public static String WarningMessage_GradleWorkspaceComposite_NameEmpty; + public static String WarningMessage_GradleWorkspaceComposite_CompositeNameExists; + public static String WarningMessage_GradleWorkspaceComposite_CompositeEmpty; + public static String InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault; public static String InfoMessage_NewGradleWorkspaceCompositeOptionsWizardPageDefault; public static String InfoMessage_NewGradleWorkspaceCompositePreviewWizardPageDefault; diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/CompositePropertyChangeListener.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/CompositePropertyChangeListener.java new file mode 100644 index 0000000000..ea76c4d5b3 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/CompositePropertyChangeListener.java @@ -0,0 +1,101 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.workspace; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Files; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.eclipse.buildship.core.internal.CorePlugin; +import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.IGradleCompositeIDs; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.ui.IWorkingSet; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; + +/** + * Listener class for {@link org.eclipse.ui.internal.dialogs.WorkingSetSelectionDialog}. Contains file composite properties file + * deletion algorithm with backup to ensure cancel function for WorkingSetSelectionDialog. + * @author kuzniarz + */ +public class CompositePropertyChangeListener implements IPropertyChangeListener { + + private final Map compositePropertiesBackup = new HashMap<>(); + IWorkingSetManager manager = PlatformUI.getWorkbench().getWorkingSetManager(); + + @Override + public void propertyChange(PropertyChangeEvent event) { + if (compositeRemovalCausedEvent(event)) { + try { + IWorkingSet removed = (IWorkingSet)event.getOldValue(); + if (isNotAggregate(removed) && removed.getId().equals(IGradleCompositeIDs.NATURE)) { + File compositePropertiesFile = CorePlugin.getInstance().getStateLocation().append("workspace-composites").append(removed.getName()).toFile(); + backupCompositeProperties(removed, compositePropertiesFile); + Files.deleteIfExists(compositePropertiesFile.toPath()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } else if (compositeAddingCausedEvent(event)) { + try { + IWorkingSet added = (IWorkingSet)event.getNewValue(); + if (isNotAggregate(added) && added.getId().equals(IGradleCompositeIDs.NATURE)) { + restoreCompositeProperties(added.getName()); + } + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + private boolean isNotAggregate(IWorkingSet removed) { + return !removed.getName().contains(":"); + } + + private void restoreCompositeProperties(String compositeName) throws FileNotFoundException, IOException { + if (this.compositePropertiesBackup.containsKey(compositeName)) { + File compositePropertiesFile = CorePlugin.getInstance().getStateLocation().append("workspace-composites").append(compositeName).toFile(); + FileOutputStream out = new FileOutputStream(compositePropertiesFile.getAbsoluteFile()); + this.compositePropertiesBackup.get(compositeName).store(out, " "); + this.compositePropertiesBackup.remove(compositeName); + out.close(); + } else { + //New Composite is being created! + } + } + + private void backupCompositeProperties(IWorkingSet removed, File compositePropertiesFile) + throws FileNotFoundException, IOException { + Properties compositeProperties = new Properties(); + FileInputStream input = new FileInputStream(compositePropertiesFile); + compositeProperties.load(input); + input.close(); + this.compositePropertiesBackup.put(removed.getName(), compositeProperties); + } + + private boolean compositeAddingCausedEvent(PropertyChangeEvent event) { + return event.getProperty().equals(IWorkingSetManager.CHANGE_WORKING_SET_ADD) && + event.getNewValue() != null; + } + + private boolean compositeRemovalCausedEvent(PropertyChangeEvent event) { + return event.getProperty().equals(IWorkingSetManager.CHANGE_WORKING_SET_REMOVE) && + event.getOldValue() != null; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/RemoveCompositeHandler.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/RemoveCompositeHandler.java new file mode 100644 index 0000000000..5f1f0fc904 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/RemoveCompositeHandler.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ +package org.eclipse.buildship.ui.internal.workspace; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.IHandler; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.handlers.HandlerUtil; + +public class RemoveCompositeHandler extends AbstractHandler implements IHandler { + + private IStructuredSelection initialSelection; + + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + // TODO Auto-generated method stub + //HandlerUtil.getActiveWorkbenchWindow(event).getWorkbench().close(); + IWorkbenchWindow activeWorkbenchWindow = HandlerUtil.getActiveWorkbenchWindow(event).getWorkbench().getActiveWorkbenchWindow(); + + if (activeWorkbenchWindow != null) { + ISelection selection= activeWorkbenchWindow.getSelectionService().getSelection(); + if (selection instanceof IStructuredSelection) { + this.initialSelection = (IStructuredSelection)selection; + } + } + return null; + } + +} diff --git a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/StartupSetup.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/StartupSetup.java new file mode 100644 index 0000000000..f63432dd21 --- /dev/null +++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/workspace/StartupSetup.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2020 Gradle Inc. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + ******************************************************************************/ + +package org.eclipse.buildship.ui.internal.workspace; + +import org.eclipse.ui.IStartup; +import org.eclipse.ui.IWorkingSetManager; +import org.eclipse.ui.PlatformUI; + +public class StartupSetup implements IStartup { + + @Override + public void earlyStartup() { + IWorkingSetManager manager = PlatformUI.getWorkbench().getWorkingSetManager(); + + manager.addPropertyChangeListener(new CompositePropertyChangeListener()); + } + +} diff --git a/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.properties b/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.properties index 82dcb3f181..7337877a6f 100644 --- a/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.properties +++ b/org.eclipse.buildship.ui/src/main/resources/org/eclipse/buildship/ui/internal/wizard/workspacecomposite/WorkspaceCompositeWizardMessages.properties @@ -9,18 +9,24 @@ # Sebastian Kuzniarz (Diebold Nixdorf Inc.) - initial API and implementation and initial documentation # +Title_GradleWorkspaceCompositeConfigurationPage=Gradle Composite Title_GradleImportOptionsWizardPage=Import Options Title_CompositeRootWizardPage=Composite Root -Title_NewGradleWorkspaceCompositeWizardPage=Create a Workspace Composite +Title_NewGradleWorkspaceCompositeWizardPage=Gradle Workspace Composite Title_NewGradleImportOptionsWizardPage=Import Options Title_NewGradleCompositeRootWizardPage=Composite Root Label_CompositeName=Composite name +WarningMessage_GradleWorkspaceComposite_NameWhitespaces=Composite names should not contain whitespaces +WarningMessage_GradleWorkspaceComposite_NameEmpty=Please enter a composite name +WarningMessage_GradleWorkspaceComposite_CompositeNameExists=Composite name already exists +WarningMessage_GradleWorkspaceComposite_CompositeEmpty=Gradle Composite does not have any elements + InfoMessage_CompositeRootWizardPageDefault=Specify an optional Root Project to apply when creating and interacting with the Gradle composite. -InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault=Enter a composite name. +InfoMessage_NewGradleWorkspaceCompositeWizardPageDefault=Specify composite name and Gradle projects to be included in Gradle composite. InfoMessage_NewGradleWorkspaceCompositeOptionsWizardPageDefault=Specify optional import options to apply when creating and interacting with the Gradle composite. InfoMessage_NewGradleWorkspaceCompositePreviewWizardPageDefault=Specify an optional Root Project to apply when creating and interacting with the Gradle composite.