blob: a46f9acdeb707de7a8f387d386480992cf43ddef [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2004, 2008 Eugene Kuleshov 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:
* Eugene Kuleshov - initial API and implementation
* Tasktop Technologies - improvements
*******************************************************************************/
package org.eclipse.mylyn.internal.tasks.ui.workingsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.runtime.PlatformObject;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.ImageDescriptor;
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.ILabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.mylyn.internal.tasks.core.AbstractTaskCategory;
import org.eclipse.mylyn.internal.tasks.core.AbstractTaskContainer;
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
import org.eclipse.mylyn.internal.tasks.ui.util.TasksUiInternal;
import org.eclipse.mylyn.internal.tasks.ui.views.TaskRepositoryLabelProvider;
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
import org.eclipse.mylyn.tasks.core.TaskRepository;
import org.eclipse.mylyn.tasks.ui.TaskElementLabelProvider;
import org.eclipse.mylyn.tasks.ui.TasksUi;
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
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.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.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.IWorkingSetPage;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.model.IWorkbenchAdapter;
import org.eclipse.ui.model.WorkbenchLabelProvider;
/**
* Adapted from org.eclipse.ui.internal.ide.dialogs.ResourceWorkingSetPage
*
* @author Eugene Kuleshov
* @author Mik Kersten
*/
public class TaskWorkingSetPage 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 treeViewer;
private IWorkingSet workingSet;
private final WorkingSetPageContentProvider workingSetPageContentProvider = new WorkingSetPageContentProvider();
private boolean firstCheck = false;
private final class WorkingSetPageContentProvider implements ITreeContentProvider {
private ElementCategory tasksContainer;
private ElementCategory resourcesContainer;
private final Map<IRepositoryQuery, TaskRepository> queryMap = new HashMap<IRepositoryQuery, TaskRepository>();
private final Map<IProject, TaskRepositoryProjectMapping> projectMap = new HashMap<IProject, TaskRepositoryProjectMapping>();
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof List) {
List<IAdaptable> taskRepositoriesContainers = new ArrayList<IAdaptable>();
List<IAdaptable> resourcesRepositoriesContainers = new ArrayList<IAdaptable>();
for (AbstractTaskContainer category : TasksUiInternal.getTaskList().getCategories()) {
taskRepositoriesContainers.add(category);
}
IProject[] projects = ResourcesPlugin.getWorkspace().getRoot().getProjects();
Set<IProject> unmappedProjects = new HashSet<IProject>();
for (Object container : (List<?>) parentElement) {
if (container instanceof TaskRepository) {
// NOTE: looking down, high complexity
if (hasChildren(container)) {
taskRepositoriesContainers.add((TaskRepository) container);
}
// NOTE: O(n^2) complexity, could fix
Set<IProject> mappedProjects = new HashSet<IProject>();
for (IProject project : projects) {
TaskRepository taskRepository = TasksUiPlugin.getDefault()
.getRepositoryForResource(project);
if (container.equals(taskRepository)) {
mappedProjects.add(project);
} else if (taskRepository == null) {
unmappedProjects.add(project);
}
}
if (!mappedProjects.isEmpty()) {
TaskRepositoryProjectMapping projectMapping = new TaskRepositoryProjectMapping(
(TaskRepository) container, mappedProjects);
resourcesRepositoriesContainers.add(projectMapping);
for (IProject mappedProject : mappedProjects) {
projectMap.put(mappedProject, projectMapping);
}
}
}
}
resourcesRepositoriesContainers.addAll(unmappedProjects);
tasksContainer = new ElementCategory(Messages.TaskWorkingSetPage_Tasks, taskRepositoriesContainers);
resourcesContainer = new ElementCategory(Messages.TaskWorkingSetPage_Resources,
resourcesRepositoriesContainers);
return new Object[] { tasksContainer, resourcesContainer };
} else if (parentElement instanceof TaskRepository) {
List<IAdaptable> taskContainers = new ArrayList<IAdaptable>();
for (AbstractTaskContainer element : TasksUiPlugin.getTaskList().getRepositoryQueries(
((TaskRepository) parentElement).getRepositoryUrl())) {
if (element instanceof IRepositoryQuery) {
taskContainers.add(element);
queryMap.put((IRepositoryQuery) element, (TaskRepository) parentElement);
}
}
return taskContainers.toArray();
} else if (parentElement instanceof TaskRepositoryProjectMapping) {
return ((TaskRepositoryProjectMapping) parentElement).getProjects().toArray();
} else if (parentElement instanceof ElementCategory) {
return ((ElementCategory) parentElement).getChildren(parentElement);
} else {
return new Object[0];
}
}
public boolean hasChildren(Object element) {
return getChildren(element).length > 0;
}
public Object[] getElements(Object element) {
return getChildren(element);
}
public Object getParent(Object element) {
if (element instanceof AbstractTaskCategory || element instanceof TaskRepository) {
return tasksContainer;
} else if (element instanceof IRepositoryQuery) {
return queryMap.get(element);
} else if (element instanceof TaskRepositoryProjectMapping) {
return resourcesContainer;
} else if (element instanceof IProject) {
Object repository = projectMap.get(element);
if (repository != null) {
return repository;
} else {
return resourcesContainer;
}
} else {
return null;
}
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
private class TaskRepositoryProjectMapping extends PlatformObject {
private final TaskRepository taskRepository;
private final Set<IProject> projects;
public TaskRepositoryProjectMapping(TaskRepository taskRepository, Set<IProject> mappedProjects) {
this.taskRepository = taskRepository;
this.projects = mappedProjects;
}
public Set<IProject> getProjects() {
return projects;
}
public TaskRepository getTaskRepository() {
return taskRepository;
}
}
class ElementCategory extends PlatformObject implements IWorkbenchAdapter {
private final String label;
private final List<IAdaptable> children;
public ElementCategory(String label, List<IAdaptable> children) {
this.label = label;
this.children = children;
}
public Object[] getChildren(Object o) {
return children.toArray();
}
public ImageDescriptor getImageDescriptor(Object object) {
return WorkbenchImages.getImageDescriptor(IWorkbenchGraphicConstants.IMG_OBJ_WORKING_SETS);
}
public String getLabel(Object o) {
return label;
}
public Object getParent(Object o) {
return null;
}
}
class AggregateLabelProvider implements ILabelProvider {
private final TaskElementLabelProvider taskLabelProvider = new TaskElementLabelProvider(false);
private final TaskRepositoryLabelProvider taskRepositoryLabelProvider = new TaskRepositoryLabelProvider();
private final WorkbenchLabelProvider workbenchLabelProvider = new WorkbenchLabelProvider();
public Image getImage(Object element) {
if (element instanceof AbstractTaskContainer) {
return taskLabelProvider.getImage(element);
} else if (element instanceof TaskRepository) {
return taskRepositoryLabelProvider.getImage(element);
} else if (element instanceof TaskRepositoryProjectMapping) {
return getImage(((TaskRepositoryProjectMapping) element).getTaskRepository());
} else {
return workbenchLabelProvider.getImage(element);
}
}
public String getText(Object element) {
if (element instanceof AbstractTaskContainer) {
return taskLabelProvider.getText(element);
} else if (element instanceof TaskRepository) {
return taskRepositoryLabelProvider.getText(element);
} else if (element instanceof TaskRepositoryProjectMapping) {
return getText(((TaskRepositoryProjectMapping) element).getTaskRepository());
} else {
return workbenchLabelProvider.getText(element);
}
}
public void addListener(ILabelProviderListener listener) {
}
public void dispose() {
}
public boolean isLabelProperty(Object element, String property) {
return false;
}
public void removeListener(ILabelProviderListener listener) {
}
}
class CustomSorter extends ViewerSorter {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
if (e1 instanceof TaskRepository || e1 instanceof TaskRepositoryProjectMapping) {
return -1;
} else if (e2 instanceof TaskRepository || e2 instanceof TaskRepositoryProjectMapping) {
return 1;
} else if (e1 instanceof ElementCategory
&& ((ElementCategory) e1).getLabel(e1).equals(Messages.TaskWorkingSetPage_Tasks)) {
return -1;
} else if (e2 instanceof ElementCategory
&& ((ElementCategory) e1).getLabel(e1).equals(Messages.TaskWorkingSetPage_Tasks)) {
return 1;
} else {
return super.compare(viewer, e1, e2);
}
}
}
public TaskWorkingSetPage() {
super("taskWorkingSetPage", Messages.TaskWorkingSetPage_Select_Working_Set_Elements, null); //$NON-NLS-1$
setDescription(Messages.TaskWorkingSetPage_Page_Description);
setImageDescriptor(TasksUiImages.BANNER_WORKING_SET);
}
public void finish() {
Object[] elements = treeViewer.getCheckedElements();
Set<IAdaptable> validElements = new HashSet<IAdaptable>();
for (Object element : elements) {
if (element instanceof AbstractTaskContainer || element instanceof IProject) {
validElements.add((IAdaptable) element);
}
}
addSpecialContainers(validElements);
if (workingSet == null) {
IWorkingSetManager workingSetManager = PlatformUI.getWorkbench().getWorkingSetManager();
workingSet = workingSetManager.createWorkingSet(getWorkingSetName(),
validElements.toArray(new IAdaptable[validElements.size()]));
} else {
workingSet.setName(getWorkingSetName());
workingSet.setElements(validElements.toArray(new IAdaptable[validElements.size()]));
}
}
private void addSpecialContainers(Set<IAdaptable> validElements) {
HashSet<AbstractTaskContainer> specialContainers = new HashSet<AbstractTaskContainer>();
for (IAdaptable element : validElements) {
if (element instanceof IRepositoryQuery) {
IRepositoryQuery query = (IRepositoryQuery) element;
if (query.getRepositoryUrl() != null) {
// Add Unmatched
AbstractTaskContainer orphansContainer = TasksUiPlugin.getTaskList().getUnmatchedContainer(
query.getRepositoryUrl());
if (orphansContainer != null) {
specialContainers.add(orphansContainer);
}
// Add Unsubmitted
AbstractTaskContainer unsubmittedContainer = TasksUiPlugin.getTaskList().getUnsubmittedContainer(
query.getRepositoryUrl());
if (unsubmittedContainer != null) {
specialContainers.add(unsubmittedContainer);
}
}
}
}
validElements.addAll(specialContainers);
}
public IWorkingSet getSelection() {
return workingSet;
}
public void setSelection(IWorkingSet workingSet) {
this.workingSet = workingSet;
if (getShell() != null && text != null) {
firstCheck = true;
initializeCheckedState();
text.setText(workingSet.getName());
}
}
private String getWorkingSetName() {
return text.getText();
}
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite composite = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
layout.marginWidth = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN);
layout.marginHeight = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
composite.setLayout(layout);
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(""); //$NON-NLS-1$
label.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER));
text = new Text(composite, SWT.SINGLE | SWT.BORDER);
text.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
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(""); //$NON-NLS-1$
label.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL
| GridData.VERTICAL_ALIGN_CENTER));
treeViewer = new CheckboxTreeViewer(composite);
treeViewer.setUseHashlookup(true);
treeViewer.setContentProvider(workingSetPageContentProvider);
treeViewer.setLabelProvider(new DecoratingLabelProvider(new AggregateLabelProvider(), PlatformUI.getWorkbench()
.getDecoratorManager()
.getLabelDecorator()));
treeViewer.setSorter(new CustomSorter());
ArrayList<Object> containers = new ArrayList<Object>();
for (TaskRepository repository : TasksUi.getRepositoryManager().getAllRepositories()) {
containers.add(repository);
}
containers.addAll(Arrays.asList(ResourcesPlugin.getWorkspace().getRoot().getProjects()));
treeViewer.setInput(containers);
// tree.setComparator(new ResourceComparator(ResourceComparator.NAME));
GridData data = new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL);
data.heightHint = SIZING_SELECTION_WIDGET_HEIGHT;
data.widthHint = SIZING_SELECTION_WIDGET_WIDTH;
treeViewer.getControl().setLayoutData(data);
treeViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(CheckStateChangedEvent event) {
handleCheckStateChange(event);
}
});
// Add select / deselect all buttons for bug 46669
Composite buttonComposite = new Composite(composite, SWT.NONE);
layout = new GridLayout(2, false);
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
buttonComposite.setLayout(layout);
buttonComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
selectAllButton.setText(Messages.TaskWorkingSetPage_Select_All);
selectAllButton.setToolTipText(""); //$NON-NLS-1$
selectAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
treeViewer.setCheckedElements(workingSetPageContentProvider.getElements(treeViewer.getInput()));
validateInput();
}
});
setButtonLayoutData(selectAllButton);
Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
deselectAllButton.setText(Messages.TaskWorkingSetPage_Deselect_All);
deselectAllButton.setToolTipText(""); //$NON-NLS-1$
deselectAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
treeViewer.setCheckedElements(new Object[0]);
validateInput();
}
});
setButtonLayoutData(deselectAllButton);
if (workingSet != null) {
for (Object object : workingSet.getElements()) {
treeViewer.expandToLevel(object, 1);
}
} else {
treeViewer.expandToLevel(2);
}
initializeCheckedState();
if (workingSet != null) {
text.setText(workingSet.getName());
}
setPageComplete(false);
Dialog.applyDialogFont(composite);
}
private void initializeCheckedState() {
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
public void run() {
Object[] items = null;
if (workingSet != null) {
items = workingSet.getElements();
if (items != null) {
// see bug 191342
treeViewer.setCheckedElements(new Object[] {});
for (Object item : items) {
if (item != null) {
treeViewer.setChecked(item, true);
}
}
}
}
}
});
}
protected void handleCheckStateChange(final CheckStateChangedEvent event) {
BusyIndicator.showWhile(getShell().getDisplay(), new Runnable() {
public void run() {
IAdaptable element = (IAdaptable) event.getElement();
handleCheckStateChangeHelper(event, element);
validateInput();
}
private void handleCheckStateChangeHelper(final CheckStateChangedEvent event, IAdaptable element) {
if (element instanceof AbstractTaskContainer || element instanceof IProject) {
treeViewer.setGrayed(element, false);
} else if (element instanceof ElementCategory) {
for (Object child : ((ElementCategory) element).getChildren(null)) {
treeViewer.setChecked(child, event.getChecked());
if (child instanceof IAdaptable) {
handleCheckStateChangeHelper(event, (IAdaptable) child);
}
}
} else if (element instanceof TaskRepository || element instanceof TaskRepositoryProjectMapping) {
for (Object child : workingSetPageContentProvider.getChildren(element)) {
treeViewer.setChecked(child, event.getChecked());
}
}
}
});
}
protected void validateInput() {
String errorMessage = null;
String infoMessage = null;
String newText = text.getText();
if (!newText.equals(newText.trim())) {
errorMessage = Messages.TaskWorkingSetPage_The_name_must_not_have_a_leading_or_trailing_whitespace;
} else if (firstCheck) {
firstCheck = false;
return;
}
if ("".equals(newText)) { //$NON-NLS-1$
errorMessage = Messages.TaskWorkingSetPage_The_name_must_not_be_empty;
}
if (errorMessage == null && (workingSet == null || !newText.equals(workingSet.getName()))) {
IWorkingSet[] workingSets = PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets();
for (IWorkingSet workingSet2 : workingSets) {
if (newText.equals(workingSet2.getName())) {
errorMessage = Messages.TaskWorkingSetPage_A_working_set_with_the_same_name_already_exists;
}
}
}
if (treeViewer.getCheckedElements().length == 0) {
infoMessage = Messages.TaskWorkingSetPage_No_categories_queries_selected;
}
setMessage(infoMessage, INFORMATION);
setErrorMessage(errorMessage);
setPageComplete(errorMessage == null);
}
}