/*******************************************************************************
* Copyright (c) 2007 Spring IDE Developers
* 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:
* Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.ui.workingsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.eclipse.core.internal.resources.WorkspaceRoot;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.fieldassist.FieldAssistColors;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
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.graphics.Image;
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.Text;
import org.eclipse.ui.IPersistableElement;
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.IDEWorkbenchPlugin;
import org.springframework.ide.eclipse.core.model.ISpringProject;
import org.springframework.ide.eclipse.ui.SpringUIImages;
import org.springframework.ide.eclipse.ui.internal.navigator.SpringNavigatorContentProvider;
import org.springframework.ide.eclipse.ui.internal.navigator.SpringNavigatorLabelProvider;
/**
* @author Christian Dupuis
* @author Torsten Juergeleit
* @since 2.0
*/
@SuppressWarnings("restriction")
public class SpringWorkingSetPage extends WizardPage implements IWorkingSetPage {
public class SpringExplorerAdaptingContentProvider implements
ITreeContentProvider {
private Set<ITreeContentProvider> contentProviders = WorkingSetUtils.getContentProvider();
private ITreeContentProvider rootContentProvider = new SpringNavigatorContentProvider();
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
public Object[] getChildren(Object parentElement) {
Set<Object> children = new HashSet<Object>();
for (ITreeContentProvider contentProvider : contentProviders) {
children.addAll(Arrays.asList(contentProvider
.getChildren(parentElement)));
}
return children.toArray();
}
public Object getParent(Object element) {
for (ITreeContentProvider contentProvider : contentProviders) {
Object parent = contentProvider.getParent(element);
if (parent != null) {
return parent;
}
}
return null;
}
public boolean hasChildren(Object element) {
Set<Object> children = new HashSet<Object>();
for (ITreeContentProvider contentProvider : contentProviders) {
children.addAll(Arrays.asList(contentProvider
.getChildren(element)));
}
return children.size() > 0;
}
public Object[] getElements(Object inputElement) {
if (inputElement instanceof WorkspaceRoot) {
return rootContentProvider.getElements(inputElement);
}
else {
Set<Object> children = new HashSet<Object>();
for (ITreeContentProvider contentProvider : contentProviders) {
children.addAll(Arrays.asList(contentProvider
.getElements(inputElement)));
}
return children.toArray();
}
}
}
private class SpringExplorerAdaptingLabelProvider implements ILabelProvider {
private Set<IElementSpecificLabelProvider> labelProviders = WorkingSetUtils.getLabelProvider();
private ILabelProvider rootLabelProviders = new SpringNavigatorLabelProvider();
public Image getImage(Object element) {
if (element instanceof ISpringProject) {
return rootLabelProviders.getImage(element);
}
else {
for (IElementSpecificLabelProvider labelProvider : labelProviders) {
if (labelProvider.supportsElement(element)) {
return labelProvider.getImage(element);
}
}
}
return rootLabelProviders.getImage(element);
}
public String getText(Object element) {
if (element instanceof ISpringProject) {
return rootLabelProviders.getText(element);
}
else {
for (IElementSpecificLabelProvider labelProvider : labelProviders) {
if (labelProvider.supportsElement(element)) {
return labelProvider.getText(element);
}
}
}
return rootLabelProviders.getText(element);
}
public void addListener(ILabelProviderListener listener) {
}
public void dispose() {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
}
}
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
private ITreeContentProvider contentProvider = new SpringExplorerAdaptingContentProvider();
public SpringWorkingSetPage() {
super("springWorkingSet", "Spring Working Set", SpringUIImages.DESC_WIZ_WORKINGSET);
setDescription("Enter a working set name and select the working set elements.");
}
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);
Label label = new Label(composite, SWT.WRAP);
label.setText("Working set name:");
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();
text.setBackground(FieldAssistColors
.getRequiredFieldBackgroundColor(text));
label = new Label(composite, SWT.WRAP);
label.setText("Working set &contents:");
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 SpringExplorerAdaptingContentProvider();
tree.setContentProvider(treeContentProvider);
tree.setLabelProvider(new SpringExplorerAdaptingLabelProvider());
tree.setSorter(new ViewerSorter());
tree.setInput(IDEWorkbenchPlugin.getPluginWorkspace().getRoot());
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(element, tree
.getChecked(element), false);
}
});
}
}
});
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("Select &All");
selectAllButton
.setToolTipText("Select all of theses resource for this working set.");
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("Dese&lect All");
deselectAllButton
.setToolTipText("Deselect all of these resources for this working set.");
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
*/
private void findCheckedResources(List<IAdaptable> checkedResources,
Object[] checkedElements) {
for (Object checkedElement : checkedElements) {
if (checkedElement instanceof IFile) {
Object[] children = contentProvider.getChildren(checkedElement);
if (children != null && children.length == 1) {
checkedElement = children[0];
}
}
if (isValidPersistableElement(checkedElement)) {
checkedResources.add((IAdaptable) checkedElement);
}
}
}
private boolean isValidPersistableElement(Object checkedElement) {
return checkedElement instanceof IAdaptable
&& ((IAdaptable) checkedElement)
.getAdapter(IPersistableElement.class) != null;
}
public void finish() {
List<IAdaptable> resources = new ArrayList<IAdaptable>(10);
findCheckedResources(resources, tree.getCheckedElements());
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()]));
}
}
public IWorkingSet getSelection() {
return workingSet;
}
private String getWorkingSetName() {
return text.getText();
}
private void handleCheckStateChange(final CheckStateChangedEvent event) {
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
public void run() {
boolean state = event.getChecked();
setSubtreeChecked(event.getElement(), state, true);
updateParentState(event.getElement());
validateInput();
}
});
}
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];
IResource resource = null;
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 if (resource != null){
updateParentState(resource);
}
else {
updateParentState(item);
}
}
}
});
}
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());
}
}
private void setSubtreeChecked(Object container, boolean state,
boolean checkExpandedState) {
// checked state is set lazily on expand, don't set it if container is
// collapsed
Object[] members = contentProvider.getChildren(container);
for (int i = members.length - 1; i >= 0; i--) {
Object 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
if ((state || elementGrayChecked)) {
setSubtreeChecked(element, state, true);
}
}
}
private void updateParentState(Object child) {
if (child == null || contentProvider.getParent(child) == null) {
return;
}
Object parent = contentProvider.getParent(child);
boolean childChecked = false;
Object[] members = contentProvider.getChildren(parent);
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);
}
private void validateInput() {
String errorMessage = null;
String infoMessage = null;
String newText = text.getText();
if (newText.equals(newText.trim()) == false) {
errorMessage = " The name must not have a leading or trailing whitespace.";
}
else if (firstCheck) {
firstCheck = false;
return;
}
if (newText.equals("")) { //$NON-NLS-1$
errorMessage = " The name must not be empty.";
}
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 = " A working set with the same name already exists.";
}
}
}
if (infoMessage == null && tree.getCheckedElements().length == 0) {
infoMessage = " No resources selected.";
}
setMessage(infoMessage, INFORMATION);
setErrorMessage(errorMessage);
setPageComplete(errorMessage == null);
}
}