blob: bf4d997ffb03be82b16789bd16d0df58cf234bd6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.ide.dialogs;
import java.util.TreeSet;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.IWorkspaceDescription;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.preference.FieldEditor;
import org.eclipse.jface.preference.IntegerFieldEditor;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
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.List;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.actions.GlobalBuildAction;
import org.eclipse.ui.dialogs.ListSelectionDialog;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.internal.util.PrefUtil;
/**
* Page used to determine what order projects will be built in
* by the workspace.
*/
public class BuildOrderPreferencePage extends PreferencePage implements
IWorkbenchPreferencePage {
private IWorkbench workbench;
private Button defaultOrderButton;
private Label buildLabel;
private List buildList;
private Composite buttonComposite;
private IntegerFieldEditor maxItersField;
private String[] defaultBuildOrder;
private String[] customBuildOrder;
//Boolean to indicate if we have looked it up
private boolean notCheckedBuildOrder = true;
private final String UP_LABEL = IDEWorkbenchMessages.BuildOrderPreference_up;
private final String DOWN_LABEL = IDEWorkbenchMessages.BuildOrderPreference_down;
private final String ADD_LABEL = IDEWorkbenchMessages.BuildOrderPreference_add;
private final String REMOVE_LABEL = IDEWorkbenchMessages.BuildOrderPreference_remove;
private final String PROJECT_SELECTION_MESSAGE = IDEWorkbenchMessages.BuildOrderPreference_selectOtherProjects;
private final String DEFAULTS_LABEL = IDEWorkbenchMessages.BuildOrderPreference_useDefaults;
private final String LIST_LABEL = IDEWorkbenchMessages.BuildOrderPreference_projectBuildOrder;
private final String NOTE_LABEL = IDEWorkbenchMessages.Preference_note;
private final String REMOVE_MESSAGE = IDEWorkbenchMessages.BuildOrderPreference_removeNote;
// whether or not the use defaults option was selected when Apply (or OK) was last pressed
// (or when the preference page was opened). This represents the most recent applied state.
private boolean defaultOrderInitiallySelected;
private IPropertyChangeListener validityChangeListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
if (event.getProperty().equals(FieldEditor.IS_VALID))
updateValidState();
}
};
/**
* Add another project to the list at the end.
*/
private void addProject() {
String[] currentItems = this.buildList.getItems();
IProject[] allProjects = getWorkspace().getRoot().getProjects();
ILabelProvider labelProvider = new LabelProvider() {
public String getText(Object element) {
return (String) element;
}
};
SimpleListContentProvider contentsProvider = new SimpleListContentProvider();
contentsProvider
.setElements(sortedDifference(allProjects, currentItems));
ListSelectionDialog dialog = new ListSelectionDialog(this.getShell(),
this, contentsProvider, labelProvider,
PROJECT_SELECTION_MESSAGE);
if (dialog.open() != Window.OK)
return;
Object[] result = dialog.getResult();
int currentItemsLength = currentItems.length;
int resultLength = result.length;
String[] newItems = new String[currentItemsLength + resultLength];
System.arraycopy(currentItems, 0, newItems, 0, currentItemsLength);
System
.arraycopy(result, 0, newItems, currentItemsLength,
result.length);
this.buildList.setItems(newItems);
}
/**
* Updates the valid state of the page.
*/
private void updateValidState() {
setValid(maxItersField.isValid());
}
/**
* Create the list of build paths. If the current build order is empty make the list empty
* and disable it.
* @param composite - the parent to create the list in
* @param enabled - the boolean that indcates if the list will be sensitive initially or not
*/
private void createBuildOrderList(Composite composite, boolean enabled) {
Font font = composite.getFont();
this.buildLabel = new Label(composite, SWT.NONE);
this.buildLabel.setText(LIST_LABEL);
this.buildLabel.setEnabled(enabled);
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
this.buildLabel.setLayoutData(gridData);
this.buildLabel.setFont(font);
this.buildList = new List(composite, SWT.BORDER | SWT.MULTI
| SWT.H_SCROLL | SWT.V_SCROLL);
this.buildList.setEnabled(enabled);
GridData data = new GridData();
//Set heightHint with a small value so the list size will be defined by
//the space available in the dialog instead of resizing the dialog to
//fit all the items in the list.
data.heightHint = buildList.getItemHeight();
data.verticalAlignment = GridData.FILL;
data.horizontalAlignment = GridData.FILL;
data.grabExcessHorizontalSpace = true;
data.grabExcessVerticalSpace = true;
this.buildList.setLayoutData(data);
this.buildList.setFont(font);
}
/**
* Create the widgets that are used to determine the build order.
*
* @param parent the parent composite
* @return the new control
*/
protected Control createContents(Composite parent) {
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
IIDEHelpContextIds.BUILD_ORDER_PREFERENCE_PAGE);
Font font = parent.getFont();
//The main composite
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginWidth = 0;
layout.marginHeight = 0;
composite.setLayout(layout);
GridData data = new GridData();
data.verticalAlignment = GridData.FILL;
data.horizontalAlignment = GridData.FILL;
composite.setLayoutData(data);
composite.setFont(font);
String[] buildOrder = getCurrentBuildOrder();
boolean useDefault = (buildOrder == null);
createDefaultPathButton(composite, useDefault);
// List always enabled so user can scroll list.
// Only the buttons need to be disabled.
createBuildOrderList(composite, true);
createListButtons(composite, !useDefault);
Composite noteComposite = createNoteComposite(font, composite,
NOTE_LABEL, REMOVE_MESSAGE);
GridData noteData = new GridData();
noteData.horizontalSpan = 2;
noteComposite.setLayoutData(noteData);
createSpacer(composite);
createMaxIterationsField(composite);
createSpacer(composite);
if (useDefault) {
this.buildList.setItems(getDefaultProjectOrder());
} else {
this.buildList.setItems(buildOrder);
}
return composite;
}
/**
* Adds in a spacer.
*
* @param composite the parent composite
*/
private void createSpacer(Composite composite) {
Label spacer = new Label(composite, SWT.NONE);
GridData spacerData = new GridData();
spacerData.horizontalSpan = 2;
spacer.setLayoutData(spacerData);
}
/**
* Create the default path button. Set it to selected based on the current workspace
* build path.
* @param composite org.eclipse.swt.widgets.Composite
* @param selected - the boolean that indicates the buttons initial state
*/
private void createDefaultPathButton(Composite composite, boolean selected) {
defaultOrderInitiallySelected = selected;
this.defaultOrderButton = new Button(composite, SWT.LEFT | SWT.CHECK);
this.defaultOrderButton.setSelection(selected);
this.defaultOrderButton.setText(DEFAULTS_LABEL);
SelectionListener listener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
defaultsButtonSelected(defaultOrderButton.getSelection());
}
};
this.defaultOrderButton.addSelectionListener(listener);
GridData gridData = new GridData();
gridData.horizontalAlignment = GridData.FILL;
gridData.horizontalSpan = 2;
this.defaultOrderButton.setLayoutData(gridData);
this.defaultOrderButton.setFont(composite.getFont());
}
/**
* Create the buttons used to manipulate the list. These Add, Remove and Move Up or Down
* the list items.
* @param composite the parent of the buttons
* @param enableComposite - boolean that indicates if a composite should be enabled
*/
private void createListButtons(Composite composite, boolean enableComposite) {
Font font = composite.getFont();
//Create an intermeditate composite to keep the buttons in the same column
this.buttonComposite = new Composite(composite, SWT.RIGHT);
GridLayout layout = new GridLayout();
layout.marginWidth = 0;
layout.marginHeight = 0;
this.buttonComposite.setLayout(layout);
GridData gridData = new GridData();
gridData.verticalAlignment = GridData.FILL;
gridData.horizontalAlignment = GridData.FILL;
this.buttonComposite.setLayoutData(gridData);
this.buttonComposite.setFont(font);
Button upButton = new Button(this.buttonComposite, SWT.CENTER
| SWT.PUSH);
upButton.setText(UP_LABEL);
upButton.setEnabled(enableComposite);
upButton.setFont(font);
setButtonLayoutData(upButton);
SelectionListener listener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
moveSelectionUp();
}
};
upButton.addSelectionListener(listener);
Button downButton = new Button(this.buttonComposite, SWT.CENTER
| SWT.PUSH);
downButton.setText(DOWN_LABEL);
downButton.setEnabled(enableComposite);
listener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
moveSelectionDown();
}
};
downButton.addSelectionListener(listener);
downButton.setFont(font);
setButtonLayoutData(downButton);
Button addButton = new Button(this.buttonComposite, SWT.CENTER
| SWT.PUSH);
addButton.setText(ADD_LABEL);
listener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
addProject();
}
};
addButton.addSelectionListener(listener);
addButton.setEnabled(enableComposite);
addButton.setFont(font);
setButtonLayoutData(addButton);
Button removeButton = new Button(this.buttonComposite, SWT.CENTER
| SWT.PUSH);
removeButton.setText(REMOVE_LABEL);
listener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
removeSelection();
}
};
removeButton.addSelectionListener(listener);
removeButton.setEnabled(enableComposite);
removeButton.setFont(font);
setButtonLayoutData(removeButton);
}
/**
* Create the field for the maximum number of iterations in the presence
* of cycles.
*/
private void createMaxIterationsField(Composite composite) {
Composite maxItersComposite = new Composite(composite, SWT.NONE);
GridData gd = new GridData(GridData.FILL_HORIZONTAL);
maxItersComposite.setLayoutData(gd);
maxItersComposite.setFont(composite.getFont());
maxItersField = new IntegerFieldEditor(
"", IDEWorkbenchMessages.BuildOrderPreference_maxIterationsLabel, maxItersComposite) { //$NON-NLS-1$
protected void doLoad() {
Text text = getTextControl();
if (text != null) {
int value = getWorkspace().getDescription()
.getMaxBuildIterations();
text.setText(Integer.toString(value));
}
}
protected void doLoadDefault() {
Text text = getTextControl();
if (text != null) {
int value = ResourcesPlugin.getPlugin()
.getPluginPreferences().getDefaultInt(
ResourcesPlugin.PREF_MAX_BUILD_ITERATIONS);
text.setText(Integer.toString(value));
}
valueChanged();
}
protected void doStore() {
// handled specially in performOK()
throw new UnsupportedOperationException();
}
};
maxItersField.setValidRange(1, Integer.MAX_VALUE);
maxItersField.setPage(this);
maxItersField.setPreferenceStore(getPreferenceStore());
maxItersField.setPropertyChangeListener(validityChangeListener);
maxItersField.load();
}
/**
* The defaults button has been selected - update the other widgets as required.
* @param selected - whether or not the defaults button got selected
*/
private void defaultsButtonSelected(boolean selected) {
if (selected) {
setBuildOrderWidgetsEnablement(false);
//Cache the current value as the custom order
customBuildOrder = buildList.getItems();
buildList.setItems(getDefaultProjectOrder());
} else {
setBuildOrderWidgetsEnablement(true);
String[] buildOrder = getCurrentBuildOrder();
if (buildOrder == null)
buildList.setItems(getDefaultProjectOrder());
else
buildList.setItems(buildOrder);
}
}
/**
* Get the project names for the current custom build
* order stored in the workspace description.
*
* @return java.lang.String[] or null if there is no setting
*/
private String[] getCurrentBuildOrder() {
if (notCheckedBuildOrder) {
customBuildOrder = getWorkspace().getDescription().getBuildOrder();
notCheckedBuildOrder = false;
}
return customBuildOrder;
}
/**
* Get the project names in the default build order
* based on the current Workspace settings.
*
* @return java.lang.String[]
*/
private String[] getDefaultProjectOrder() {
if (defaultBuildOrder == null) {
IWorkspace workspace = getWorkspace();
IWorkspace.ProjectOrder projectOrder = getWorkspace()
.computeProjectOrder(workspace.getRoot().getProjects());
IProject[] foundProjects = projectOrder.projects;
defaultBuildOrder = new String[foundProjects.length];
int foundSize = foundProjects.length;
for (int i = 0; i < foundSize; i++) {
defaultBuildOrder[i] = foundProjects[i].getName();
}
}
return defaultBuildOrder;
}
/**
* Return the Workspace the build order is from.
* @return org.eclipse.core.resources.IWorkspace
*/
private IWorkspace getWorkspace() {
return ResourcesPlugin.getWorkspace();
}
/**
* Return whether or not searchElement is in testArray.
*/
private boolean includes(String[] testArray, String searchElement) {
for (int i = 0; i < testArray.length; i++) {
if (searchElement.equals(testArray[i]))
return true;
}
return false;
}
/**
* See IWorkbenchPreferencePage. This class does nothing with he Workbench.
*/
public void init(IWorkbench workbench) {
this.workbench = workbench;
setPreferenceStore(PrefUtil.getInternalPreferenceStore());
}
/**
* Move the current selection in the build list down.
*/
private void moveSelectionDown() {
//Only do this operation on a single selection
if (this.buildList.getSelectionCount() == 1) {
int currentIndex = this.buildList.getSelectionIndex();
if (currentIndex < this.buildList.getItemCount() - 1) {
String elementToMove = this.buildList.getItem(currentIndex);
this.buildList.remove(currentIndex);
this.buildList.add(elementToMove, currentIndex + 1);
this.buildList.select(currentIndex + 1);
}
}
}
/**
* Move the current selection in the build list up.
*/
private void moveSelectionUp() {
int currentIndex = this.buildList.getSelectionIndex();
//Only do this operation on a single selection
if (currentIndex > 0 && this.buildList.getSelectionCount() == 1) {
String elementToMove = this.buildList.getItem(currentIndex);
this.buildList.remove(currentIndex);
this.buildList.add(elementToMove, currentIndex - 1);
this.buildList.select(currentIndex - 1);
}
}
/**
* Performs special processing when this page's Defaults button has been pressed.
* In this case change the defaultOrderButton to have it's selection set to true.
*/
protected void performDefaults() {
this.defaultOrderButton.setSelection(true);
defaultsButtonSelected(true);
maxItersField.loadDefault();
super.performDefaults();
}
/**
* OK has been pressed. If the defualt button is pressed then reset the build order to false;
* otherwise set it to the contents of the list.
*/
public boolean performOk() {
String[] buildOrder = null;
boolean useDefault = defaultOrderButton.getSelection();
// if use defaults is turned off
if (!useDefault)
buildOrder = buildList.getItems();
//Get a copy of the description from the workspace, set the build order and then
//apply it to the workspace.
IWorkspaceDescription description = getWorkspace().getDescription();
description.setBuildOrder(buildOrder);
description.setMaxBuildIterations(maxItersField.getIntValue());
try {
getWorkspace().setDescription(description);
} catch (CoreException exception) {
//failed - return false
return false;
}
// Perform auto-build if use default is off (because
// order could have changed) or if use default setting
// was changed.
if (!useDefault || (useDefault != defaultOrderInitiallySelected)) {
defaultOrderInitiallySelected = useDefault;
// If auto build is turned on, then do a global incremental
// build on all the projects.
if (ResourcesPlugin.getWorkspace().isAutoBuilding()) {
GlobalBuildAction action = new GlobalBuildAction(workbench
.getActiveWorkbenchWindow(),
IncrementalProjectBuilder.INCREMENTAL_BUILD);
action.doBuild();
}
}
// Clear the custom build order cache
customBuildOrder = null;
return true;
}
/**
* Remove the current selection in the build list.
*/
private void removeSelection() {
this.buildList.remove(this.buildList.getSelectionIndices());
}
/**
* Set the widgets that select build order to be enabled or diabled.
* @param value boolean
*/
private void setBuildOrderWidgetsEnablement(boolean value) {
// Only change enablement of buttons. Leave list alone
// because you can't scroll it when disabled.
Control[] children = this.buttonComposite.getChildren();
for (int i = 0; i < children.length; i++) {
children[i].setEnabled(value);
}
}
/**
* Return a sorted array of the names of the projects that are already in the currently
* displayed names.
* @return String[]
* @param allProjects - all of the projects in the workspace
* @param currentlyDisplayed - the names of the projects already being displayed
*/
private String[] sortedDifference(IProject[] allProjects,
String[] currentlyDisplayed) {
TreeSet difference = new TreeSet();
for (int i = 0; i < allProjects.length; i++) {
if (!includes(currentlyDisplayed, allProjects[i].getName()))
difference.add(allProjects[i].getName());
}
String[] returnValue = new String[difference.size()];
difference.toArray(returnValue);
return returnValue;
}
}