blob: b748a3b2726a91423b04e739c37e2a9e6168f78a [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
* Sebastian Davids <sdavids@gmx.de> - Fix for bug 19346 - Dialog font
* should be activated and used by other components.
*******************************************************************************/
package org.eclipse.ui.internal.ide.dialogs;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
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.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.IWorkingSetPage;
import org.eclipse.ui.internal.ide.IDEInternalWorkbenchImages;
import org.eclipse.ui.internal.ide.IDEWorkbenchMessages;
import org.eclipse.ui.internal.ide.IDEWorkbenchPlugin;
import org.eclipse.ui.internal.ide.IIDEHelpContextIds;
import org.eclipse.ui.model.WorkbenchContentProvider;
import org.eclipse.ui.model.WorkbenchLabelProvider;
/**
* A resource working set page allows the user to edit an
* existing working set and create a new working set.
* <p>
* Working set elements are presented as a simple resource tree.
* </p>
*
* @since 2.0
*/
public class ResourceWorkingSetPage extends WizardPage implements
IWorkingSetPage {
private final static int SIZING_SELECTION_WIDGET_WIDTH = 50;
private final static int SIZING_SELECTION_WIDGET_HEIGHT = 200;
private Text text;
private CheckboxTreeViewer tree;
private IWorkingSet workingSet;
private boolean firstCheck = false; // set to true if selection is set in setSelection
/**
* Creates a new instance of the receiver.
*/
public ResourceWorkingSetPage() {
super(
"resourceWorkingSetPage", //$NON-NLS-1$
IDEWorkbenchMessages.ResourceWorkingSetPage_title,
IDEInternalWorkbenchImages
.getImageDescriptor(IDEInternalWorkbenchImages.IMG_WIZBAN_RESOURCEWORKINGSET_WIZ));
setDescription(IDEWorkbenchMessages.ResourceWorkingSetPage_description);
}
/**
* Adds working set elements contained in the given container to the list
* of checked resources.
*
* @param collectedResources list of collected resources
* @param container container to collect working set elements for
*/
private void addWorkingSetElements(List collectedResources,
IContainer container) {
IAdaptable[] elements = workingSet.getElements();
IPath containerPath = container.getFullPath();
for (int i = 0; i < elements.length; i++) {
IResource resource = null;
if (elements[i] instanceof IResource)
resource = (IResource) elements[i];
else
resource = (IResource) elements[i].getAdapter(IResource.class);
if (resource != null) {
IPath resourcePath = resource.getFullPath();
if (containerPath.isPrefixOf(resourcePath))
collectedResources.add(elements[i]);
}
}
}
/**
* Overrides method in WizardPage.
*
* @see org.eclipse.jface.wizard.WizardPage#createControl(Composite)
*/
public void createControl(Composite parent) {
Font font = parent.getFont();
Composite composite = new Composite(parent, SWT.NULL);
composite.setLayout(new GridLayout());
composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
setControl(composite);
PlatformUI.getWorkbench().getHelpSystem().setHelp(composite,
IIDEHelpContextIds.WORKING_SET_RESOURCE_PAGE);
Label label = new Label(composite, SWT.WRAP);
label.setText(IDEWorkbenchMessages.ResourceWorkingSetPage_message);
GridData data = new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER);
label.setLayoutData(data);
label.setFont(font);
text = new Text(composite, SWT.SINGLE | SWT.BORDER);
text.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL));
text.setFont(font);
text.addModifyListener(new ModifyListener() {
public void modifyText(ModifyEvent e) {
validateInput();
}
});
text.setFocus();
label = new Label(composite, SWT.WRAP);
label.setText(IDEWorkbenchMessages.ResourceWorkingSetPage_label_tree);
data = new GridData(GridData.GRAB_HORIZONTAL
| GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER);
label.setLayoutData(data);
label.setFont(font);
tree = new CheckboxTreeViewer(composite);
tree.setUseHashlookup(true);
final ITreeContentProvider treeContentProvider = new WorkbenchContentProvider();
tree.setContentProvider(treeContentProvider);
tree.setLabelProvider(new DecoratingLabelProvider(
new WorkbenchLabelProvider(), IDEWorkbenchPlugin.getDefault()
.getWorkbench().getDecoratorManager()
.getLabelDecorator()));
tree.setInput(IDEWorkbenchPlugin.getPluginWorkspace().getRoot());
tree.setSorter(new ResourceSorter(ResourceSorter.NAME));
data = new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL);
data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
tree.getControl().setLayoutData(data);
tree.getControl().setFont(font);
tree.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
handleCheckStateChange(event);
}
});
tree.addTreeListener(new ITreeViewerListener() {
public void treeCollapsed(TreeExpansionEvent event) {
}
public void treeExpanded(TreeExpansionEvent event) {
final Object element = event.getElement();
if (tree.getGrayed(element) == false)
BusyIndicator.showWhile(getShell().getDisplay(),
new Runnable() {
public void run() {
setSubtreeChecked((IContainer) element,
tree.getChecked(element), false);
}
});
}
});
// Add select / deselect all buttons for bug 46669
Composite buttonComposite = new Composite(composite, SWT.NONE);
buttonComposite.setLayout(new GridLayout(2, false));
buttonComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
selectAllButton.setText(IDEWorkbenchMessages.ResourceWorkingSetPage_selectAll_label);
selectAllButton.setToolTipText(IDEWorkbenchMessages.ResourceWorkingSetPage_selectAll_toolTip);
selectAllButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent selectionEvent) {
tree.setCheckedElements(treeContentProvider.getElements(tree.getInput()));
validateInput();
}
});
selectAllButton.setFont(font);
setButtonLayoutData(selectAllButton);
Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
deselectAllButton.setText(IDEWorkbenchMessages.ResourceWorkingSetPage_deselectAll_label);
deselectAllButton.setToolTipText(IDEWorkbenchMessages.ResourceWorkingSetPage_deselectAll_toolTip);
deselectAllButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent selectionEvent) {
tree.setCheckedElements(new Object[0]);
validateInput();
}
});
deselectAllButton.setFont(font);
setButtonLayoutData(deselectAllButton);
initializeCheckedState();
if (workingSet != null) {
text.setText(workingSet.getName());
}
setPageComplete(false);
}
/**
* Collects all checked resources in the specified container.
*
* @param checkedResources the output, list of checked resources
* @param container the container to collect checked resources in
*/
private void findCheckedResources(List checkedResources,
IContainer container) {
IResource[] resources = null;
try {
resources = container.members();
} catch (CoreException ex) {
handleCoreException(
ex,
getShell(),
IDEWorkbenchMessages.ResourceWorkingSetPage_error,
IDEWorkbenchMessages.ResourceWorkingSetPage_error_updateCheckedState);
}
for (int i = 0; i < resources.length; i++) {
if (tree.getGrayed(resources[i])) {
if (resources[i].isAccessible())
findCheckedResources(checkedResources,
(IContainer) resources[i]);
else
addWorkingSetElements(checkedResources,
(IContainer) resources[i]);
} else if (tree.getChecked(resources[i])) {
checkedResources.add(resources[i]);
}
}
}
/**
* Implements IWorkingSetPage.
*
* @see org.eclipse.ui.dialogs.IWorkingSetPage#finish()
*/
public void finish() {
ArrayList resources = new ArrayList(10);
findCheckedResources(resources, (IContainer) tree.getInput());
if (workingSet == null) {
IWorkingSetManager workingSetManager = PlatformUI.getWorkbench()
.getWorkingSetManager();
workingSet = workingSetManager.createWorkingSet(
getWorkingSetName(), (IAdaptable[]) resources
.toArray(new IAdaptable[resources.size()]));
} else {
workingSet.setName(getWorkingSetName());
workingSet.setElements((IAdaptable[]) resources
.toArray(new IAdaptable[resources.size()]));
}
}
/**
* Implements IWorkingSetPage.
*
* @see org.eclipse.ui.dialogs.IWorkingSetPage#getSelection()
*/
public IWorkingSet getSelection() {
return workingSet;
}
/**
* Returns the name entered in the working set name field.
*
* @return the name entered in the working set name field.
*/
private String getWorkingSetName() {
return text.getText();
}
/**
* Called when the checked state of a tree item changes.
*
* @param event the checked state change event.
*/
private void handleCheckStateChange(final CheckStateChangedEvent event) {
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
public void run() {
IResource resource = (IResource) event.getElement();
boolean state = event.getChecked();
tree.setGrayed(resource, false);
if (resource instanceof IContainer) {
setSubtreeChecked((IContainer) resource, state, true);
}
updateParentState(resource);
validateInput();
}
});
}
/**
* Displays an error message when a CoreException occured.
*
* @param exception the CoreException
* @param shell parent shell for the message box
* @param title the mesage box title
* @param message additional error message
*/
private void handleCoreException(CoreException exception, Shell shell,
String title, String message) {
IStatus status = exception.getStatus();
if (status != null) {
ErrorDialog.openError(shell, title, message, status);
} else {
MessageDialog
.openError(
shell,
IDEWorkbenchMessages.InternalError, exception.getLocalizedMessage());
}
}
/**
* Sets the checked state of tree items based on the initial
* working set, if any.
*/
private void initializeCheckedState() {
if (workingSet == null)
return;
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
public void run() {
IAdaptable[] items = workingSet.getElements();
tree.setCheckedElements(items);
for (int i = 0; i < items.length; i++) {
IAdaptable item = items[i];
IContainer container = null;
IResource resource = null;
if (item instanceof IContainer) {
container = (IContainer) item;
} else {
container = (IContainer) item
.getAdapter(IContainer.class);
}
if (container != null) {
setSubtreeChecked(container, true, true);
}
if (item instanceof IResource) {
resource = (IResource) item;
} else {
resource = (IResource) item.getAdapter(IResource.class);
}
if (resource != null && resource.isAccessible() == false) {
IProject project = resource.getProject();
if (tree.getChecked(project) == false)
tree.setGrayChecked(project, true);
} else {
updateParentState(resource);
}
}
}
});
}
/**
* Implements IWorkingSetPage.
*
* @see org.eclipse.ui.dialogs.IWorkingSetPage#setSelection(IWorkingSet)
*/
public void setSelection(IWorkingSet workingSet) {
if (workingSet == null) {
throw new IllegalArgumentException("Working set must not be null"); //$NON-NLS-1$
}
this.workingSet = workingSet;
if (getShell() != null && text != null) {
firstCheck = true;
initializeCheckedState();
text.setText(workingSet.getName());
}
}
/**
* Sets the checked state of the container's members.
*
* @param container the container whose children should be checked/unchecked
* @param state true=check all members in the container. false=uncheck all
* members in the container.
* @param checkExpandedState true=recurse into sub-containers and set the
* checked state. false=only set checked state of members of this container
*/
private void setSubtreeChecked(IContainer container, boolean state,
boolean checkExpandedState) {
// checked state is set lazily on expand, don't set it if container is collapsed
if (container.isAccessible() == false
|| (tree.getExpandedState(container) == false && state && checkExpandedState)) {
return;
}
IResource[] members = null;
try {
members = container.members();
} catch (CoreException ex) {
handleCoreException(
ex,
getShell(),
IDEWorkbenchMessages.ResourceWorkingSetPage_error,
IDEWorkbenchMessages.ResourceWorkingSetPage_error_updateCheckedState);
}
for (int i = members.length - 1; i >= 0; i--) {
IResource element = members[i];
boolean elementGrayChecked = tree.getGrayed(element)
|| tree.getChecked(element);
if (state) {
tree.setChecked(element, true);
tree.setGrayed(element, false);
} else {
tree.setGrayChecked(element, false);
}
// unchecked state only needs to be set when the container is
// checked or grayed
if (element instanceof IContainer && (state || elementGrayChecked)) {
setSubtreeChecked((IContainer) element, state, true);
}
}
}
/**
* Check and gray the resource parent if all resources of the
* parent are checked.
*
* @param child the resource whose parent checked state should
* be set.
*/
private void updateParentState(IResource child) {
if (child == null || child.getParent() == null)
return;
IContainer parent = child.getParent();
boolean childChecked = false;
IResource[] members = null;
try {
members = parent.members();
} catch (CoreException ex) {
handleCoreException(
ex,
getShell(),
IDEWorkbenchMessages.ResourceWorkingSetPage_error,
IDEWorkbenchMessages.ResourceWorkingSetPage_error_updateCheckedState);
}
for (int i = members.length - 1; i >= 0; i--) {
if (tree.getChecked(members[i]) || tree.getGrayed(members[i])) {
childChecked = true;
break;
}
}
tree.setGrayChecked(parent, childChecked);
updateParentState(parent);
}
/**
* Validates the working set name and the checked state of the
* resource tree.
*/
private void validateInput() {
String errorMessage = null;
String infoMessage= null;
String newText = text.getText();
if (newText.equals(newText.trim()) == false) {
errorMessage = IDEWorkbenchMessages.ResourceWorkingSetPage_warning_nameWhitespace;
} else if (firstCheck) {
firstCheck = false;
return;
}
if (newText.equals("")) { //$NON-NLS-1$
errorMessage = IDEWorkbenchMessages.ResourceWorkingSetPage_warning_nameMustNotBeEmpty;
}
if (errorMessage == null
&& (workingSet == null || newText.equals(workingSet.getName()) == false)) {
IWorkingSet[] workingSets = PlatformUI.getWorkbench()
.getWorkingSetManager().getWorkingSets();
for (int i = 0; i < workingSets.length; i++) {
if (newText.equals(workingSets[i].getName())) {
errorMessage = IDEWorkbenchMessages.ResourceWorkingSetPage_warning_workingSetExists;
}
}
}
if (infoMessage == null && tree.getCheckedElements().length == 0) {
infoMessage = IDEWorkbenchMessages.ResourceWorkingSetPage_warning_resourceMustBeChecked;
}
setMessage(infoMessage, INFORMATION);
setErrorMessage(errorMessage);
setPageComplete(errorMessage == null);
}
}