diff --git a/org.eclipse.buildship.ui/plugin.xml b/org.eclipse.buildship.ui/plugin.xml
index 4719cd31e6..fd1fc3cdb0 100644
--- a/org.eclipse.buildship.ui/plugin.xml
+++ b/org.eclipse.buildship.ui/plugin.xml
@@ -51,6 +51,28 @@
name="Gradle">
+
+
+
+
+
+ Create a new Gradle workspace composite.
+
+
+
+
+
+
distributionValidator;
+ private final Validator javaHomeValidator;
+ private final Validator gradleUserHomeValidator;
+
+ public GradleCompositeImportOptionsPreferencePage() {
+ this.gradleUserHomeValidator = Validators.optionalDirectoryValidator("Gradle user home");
+ this.javaHomeValidator = Validators.optionalDirectoryValidator("Java home");
+ this.distributionValidator = GradleDistributionViewModel.validator();
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+ this.gradleProjectSettingsComposite = GradleProjectSettingsComposite.builder(parent)
+ .withAutoSyncCheckbox()
+ .withOverrideCheckbox("Override workspace settings", "Configure Workspace Settings")
+ .build();
+ initValues();
+ addListeners();
+ return this.gradleProjectSettingsComposite;
+ }
+
+ private void initValues() {
+ IProject project = getTargetProject();
+ BuildConfiguration buildConfig = CorePlugin.configurationManager().loadProjectConfiguration(project).getBuildConfiguration();
+ boolean overrideWorkspaceSettings = buildConfig.isOverrideWorkspaceSettings();
+ this.gradleProjectSettingsComposite.getGradleDistributionGroup().setDistribution(GradleDistributionViewModel.from(buildConfig.getGradleDistribution()));
+ this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setGradleUserHome(buildConfig.getGradleUserHome());
+ this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setJavaHome(buildConfig.getJavaHome());
+ this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setArguments(buildConfig.getArguments());
+ this.gradleProjectSettingsComposite.getAdvancedOptionsGroup().setJvmArguments(buildConfig.getJvmArguments());
+ this.gradleProjectSettingsComposite.getOverrideBuildSettingsCheckbox().setSelection(overrideWorkspaceSettings);
+ this.gradleProjectSettingsComposite.getBuildScansCheckbox().setSelection(buildConfig.isBuildScansEnabled());
+ this.gradleProjectSettingsComposite.getOfflineModeCheckbox().setSelection(buildConfig.isOfflineMode());
+ this.gradleProjectSettingsComposite.getAutoSyncCheckbox().setSelection(buildConfig.isAutoSync());
+ this.gradleProjectSettingsComposite.getShowConsoleViewCheckbox().setSelection(buildConfig.isShowConsoleView());
+ this.gradleProjectSettingsComposite.getShowExecutionsViewCheckbox().setSelection(buildConfig.isShowExecutionsView());
+ this.gradleProjectSettingsComposite.updateEnablement();
+ }
+
+ private void addListeners() {
+ this.gradleProjectSettingsComposite.getParentPreferenceLink().addSelectionListener(new WorkbenchPreferenceOpeningSelectionListener());
+ AdvancedOptionsGroup advancedOptionsGroup = this.gradleProjectSettingsComposite.getAdvancedOptionsGroup();
+ advancedOptionsGroup.getGradleUserHomeText().addModifyListener(new ValidatingListener<>(this, () -> advancedOptionsGroup.getGradleUserHome(), this.gradleUserHomeValidator));
+ advancedOptionsGroup.getJavaHomeText().addModifyListener(new ValidatingListener<>(this, () -> advancedOptionsGroup.getJavaHome(), this.javaHomeValidator));
+ this.gradleProjectSettingsComposite.getGradleDistributionGroup().addDistributionChangedListener(new GradleDistributionValidatingListener(this, this.distributionValidator));
+ }
+
+ @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;
+ }
+
+ @SuppressWarnings("cast")
+ private IProject getTargetProject() {
+ return (IProject) Platform.getAdapterManager().getAdapter(getElement(), IProject.class);
+ }
+
+ /**
+ * Opens the workspace preferences dialog.
+ */
+ private class WorkbenchPreferenceOpeningSelectionListener implements SelectionListener {
+
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ openWorkspacePreferences();
+ }
+
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ openWorkspacePreferences();
+ }
+
+ private void openWorkspacePreferences() {
+ PreferencesUtil.createPreferenceDialogOn(getShell(), GradleWorkbenchPreferencePage.PAGE_ID, null, null).open();
+ }
+ }
+}
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
new file mode 100644
index 0000000000..1afc18af35
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleCompositeRootProjectPreferencePage.java
@@ -0,0 +1,96 @@
+/*******************************************************************************
+ * 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.preferences;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Layout;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+import org.eclipse.buildship.ui.internal.util.layout.LayoutUtils;
+import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeWizardMessages;
+
+/**
+ * Preference page for composite root project.
+ *
+ * @author Sebastian Kuzniarz
+ */
+
+public final class GradleCompositeRootProjectPreferencePage extends PropertyPage {
+
+ public static final String PAGE_ID = "org.eclipse.buildship.ui.compositeRootProjectProperties";
+
+ private Text workspaceCompositeRootProjectLabel;
+ private Text overrideCheckboxLabel;
+ private Button overrideSettingsCheckbox;
+ private Button selectRootProject;
+ private Composite rootProjectSettingsComposite;
+ private Label rootProjectLabel;
+
+ private Layout createLayout() {
+ GridLayout layout = LayoutUtils.newGridLayout(2);
+ layout.horizontalSpacing = 4;
+ layout.verticalSpacing = 4;
+ return layout;
+ }
+
+ @Override
+ protected Control createContents(Composite parent) {
+
+ this.rootProjectSettingsComposite = new Composite(parent, SWT.NONE);
+ this.rootProjectSettingsComposite.setLayout(createLayout());
+
+ this.overrideSettingsCheckbox = new Button(this.rootProjectSettingsComposite, SWT.CHECK);
+ this.overrideSettingsCheckbox.setText("Use project as composite root");
+ GridDataFactory.swtDefaults().applyTo(this.rootProjectSettingsComposite);
+
+ Label line = new Label(this.rootProjectSettingsComposite, 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);
+ 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);
+
+ // root project label
+ 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);
+
+ // root project text field
+ this.workspaceCompositeRootProjectLabel = new Text(workspaceCompositeNameComposite, SWT.BORDER);
+ this.workspaceCompositeRootProjectLabel.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.setText(WorkspaceCompositeWizardMessages.Button_Select_RootProject);
+ return this.rootProjectSettingsComposite;
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ }
+
+ @Override
+ public boolean performOk() {
+ return true;
+ }
+}
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
new file mode 100644
index 0000000000..63d52f0aa1
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/preferences/GradleWorkspaceCompositePreferencePage.java
@@ -0,0 +1,71 @@
+/*******************************************************************************
+ * 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.preferences;
+
+import org.eclipse.jface.layout.GridDataFactory;
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+import org.eclipse.ui.dialogs.PropertyPage;
+
+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.WorkspaceCompositeWizardMessages;
+
+/**
+ * Preference page for workspace composite configuration.
+ *
+ * @author Sebastian Kuzniarz
+ */
+@SuppressWarnings("unused")
+public final class GradleWorkspaceCompositePreferencePage extends PropertyPage {
+
+ public static final String PAGE_ID = "org.eclipse.buildship.ui.compositeproperties";
+
+ private Text workspaceCompositeNameText;
+ private Label compositeName;
+ private GradleProjectGroup gradleProjectCheckboxtreeComposite;
+ private Composite gradleWorkspaceCompositeSettingsComposite;
+
+ @Override
+ protected Control createContents(Composite parent) {
+ this.gradleWorkspaceCompositeSettingsComposite = new Composite(parent, SWT.FILL);
+ this.gradleWorkspaceCompositeSettingsComposite.setLayout(LayoutUtils.newGridLayout(2));
+
+ // composite name container
+ Composite workspaceCompositeNameComposite = new Composite(this.gradleWorkspaceCompositeSettingsComposite, 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(this.gradleWorkspaceCompositeSettingsComposite);
+ GridDataFactory.swtDefaults().align(SWT.FILL, SWT.FILL).grab(true, true).span(3, SWT.DEFAULT).applyTo(this.gradleProjectCheckboxtreeComposite);
+
+ return this.gradleWorkspaceCompositeSettingsComposite;
+ }
+
+ @Override
+ public boolean performOk() {
+ return true;
+ }
+}
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
new file mode 100644
index 0000000000..c23d4511b5
--- /dev/null
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/GradleProjectGroup.java
@@ -0,0 +1,85 @@
+/*******************************************************************************
+ * 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.util.widget;
+
+import org.eclipse.jface.layout.GridLayoutFactory;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Group;
+import org.eclipse.swt.widgets.Tree;
+import org.eclipse.swt.widgets.TreeItem;
+
+import org.eclipse.buildship.ui.internal.wizard.workspacecomposite.WorkspaceCompositeWizardMessages;
+
+@SuppressWarnings("unused")
+public class GradleProjectGroup extends Group {
+
+ private Font font;
+ private Button newGradleProject;
+ private Button addExternalGradleProject;
+ private Composite buttonComposite;
+ private Tree gradleProjectTree;
+
+ public GradleProjectGroup(Composite parent) {
+ super(parent, SWT.NONE);
+ setText(WorkspaceCompositeWizardMessages.Group_Label_GradleProjects);
+ createWidgets();
+ }
+
+ 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.buttonComposite = new Composite(this, SWT.NONE);
+ this.buttonComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true, 1, 1));
+ GridLayoutFactory.fillDefaults().numColumns(1).applyTo(this.buttonComposite);
+
+ this.newGradleProject = new Button(this.buttonComposite, SWT.PUSH);
+ this.newGradleProject.setText(WorkspaceCompositeWizardMessages.Button_New_GradleProject);
+ this.newGradleProject.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ this.addExternalGradleProject = new Button(this.buttonComposite, SWT.PUSH);
+ this.addExternalGradleProject.setText(WorkspaceCompositeWizardMessages.Button_Add_ExternalGradleProject);
+ this.addExternalGradleProject.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 1, 1));
+
+ fillCheckboxTreeWithFakeData();
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+ }
+
+ @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/util/widget/UiBuilder.java b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/UiBuilder.java
index e4bc15aaa7..5cb2a45d94 100644
--- a/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/UiBuilder.java
+++ b/org.eclipse.buildship.ui/src/main/java/org/eclipse/buildship/ui/internal/util/widget/UiBuilder.java
@@ -85,6 +85,16 @@ public UiBuilder alignFillHorizontal() {
return this;
}
+ /**
+ * Aligns the created widget to fill the cell vertically aligned at top.
+ *
+ * @return the builder
+ */
+ public UiBuilder alignFillVerticalTop() {
+ this.control.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, true, 1, 1));
+ return this;
+ }
+
/**
* Aligns the created widget to fill both horizontal and vertical.
*
@@ -177,6 +187,17 @@ public UiBuilder