blob: e5d28b101c719106711b037160350bdd5109306b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2011 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.ui.workingsets;
import java.util.Arrays;
import java.util.HashSet;
import org.eclipse.swt.SWT;
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.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.swt.widgets.TreeItem;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.wizard.WizardPage;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.IWorkingSetPage;
/**
* A tree viewer on the left is used to show the workspace content, a table viewer on the
* right is used to show the working set content. Buttons to move content from right
* to left and vice versa are available between the two viewers. A text field allows to
* set/change the working sets name.
*
* @since 3.1
*/
public abstract class AbstractWorkingSetWizardPage extends WizardPage implements IWorkingSetPage {
private final class AddedElementsFilter extends ViewerFilter {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
return !fSelectedElements.contains(element);
}
}
private Text fWorkingSetName;
private TreeViewer fTree;
private TableViewer fTable;
private ITreeContentProvider fTreeContentProvider;
private boolean fFirstCheck;
private final HashSet<Object> fSelectedElements;
private IWorkingSet fWorkingSet;
protected AbstractWorkingSetWizardPage(String pageName, String title, ImageDescriptor titleImage) {
super(pageName, title, titleImage);
fSelectedElements= new HashSet<>();
fFirstCheck= true;
}
/**
* Returns the page id as specified in the extension point.
* @return the page id
*/
protected abstract String getPageId();
/**
* Configure the tree viewer used on the left side of the dialog.
*
* Implementors must set:
* <ul>
* <li>The content provider</li>
* <li>The label provider</li>
* <li>The viewers input</li>
* </ul>
* They may also set:
* <ul>
* <li>The viewer comparator</li>
* <li>Any viewer filter</li>
* <li>The selection</li>
* </ul>
*
* @param tree the tree to configure
*/
protected abstract void configureTree(TreeViewer tree);
/**
* Configure the table viewer used on the right side of the dialog.
*
* Implementors must set:
* <ul>
* <li>The label provider</li>
* </ul>
* They may also set:
* <ul>
* <li>The viewer comparator</li>
* </ul>
* They must not set:
* <ul>
* <li>The viewers content provider</li>
* <li>The viewers input</li>
* <li>Any viewer filter</li>
* </ul>
*
* @param table the table to configure
*/
protected abstract void configureTable(TableViewer table);
/**
* Returns the elements which are shown in the table initially. Return an empty
* array if the table should be empty. The given working set is the working set
* which will be configured by this dialog, or <b>null</b> if it does not yet
* exist.
*
* @param workingSet the working set to configure or <b>null</b> if not yet exist
* @return the elements to show in the table
*/
protected abstract Object[] getInitialWorkingSetElements(IWorkingSet workingSet);
/*
* @see org.eclipse.jface.dialogs.IDialogPage#createControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createControl(Composite parent) {
initializeDialogUnits(parent);
Composite composite= new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout());
composite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
setControl(composite);
Label label= new Label(composite, SWT.WRAP);
label.setText(WorkingSetMessages.JavaWorkingSetPage_workingSet_name);
GridData gd= new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER);
label.setLayoutData(gd);
fWorkingSetName= new Text(composite, SWT.SINGLE | SWT.BORDER);
fWorkingSetName.setLayoutData(new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL));
fWorkingSetName.addModifyListener(
new ModifyListener() {
@Override
public void modifyText(ModifyEvent e) {
validateInput();
}
}
);
Composite leftCenterRightComposite= new Composite(composite, SWT.NONE);
GridData gridData= new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.heightHint= convertHeightInCharsToPixels(20);
leftCenterRightComposite.setLayoutData(gridData);
GridLayout gridLayout= new GridLayout(3, false);
gridLayout.marginHeight= 0;
gridLayout.marginWidth= 0;
leftCenterRightComposite.setLayout(gridLayout);
Composite leftComposite= new Composite(leftCenterRightComposite, SWT.NONE);
gridData= new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.widthHint= convertWidthInCharsToPixels(40);
leftComposite.setLayoutData(gridData);
gridLayout= new GridLayout(1, false);
gridLayout.marginHeight= 0;
gridLayout.marginWidth= 0;
leftComposite.setLayout(gridLayout);
Composite centerComposite = new Composite(leftCenterRightComposite, SWT.NONE);
gridLayout= new GridLayout(1, false);
gridLayout.marginHeight= 0;
gridLayout.marginWidth= 0;
centerComposite.setLayout(gridLayout);
centerComposite.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false));
Composite rightComposite= new Composite(leftCenterRightComposite, SWT.NONE);
gridData= new GridData(SWT.FILL, SWT.FILL, true, true);
gridData.widthHint= convertWidthInCharsToPixels(40);
rightComposite.setLayoutData(gridData);
gridLayout= new GridLayout(1, false);
gridLayout.marginHeight= 0;
gridLayout.marginWidth= 0;
rightComposite.setLayout(gridLayout);
createTree(leftComposite);
createTable(rightComposite);
if (fWorkingSet != null)
fWorkingSetName.setText(fWorkingSet.getName());
initializeSelectedElements();
validateInput();
fTable.setInput(fSelectedElements);
fTable.refresh(true);
fTree.refresh(true);
createButtonBar(centerComposite);
fWorkingSetName.setFocus();
fWorkingSetName.setSelection(0, fWorkingSetName.getText().length());
Dialog.applyDialogFont(composite);
}
private void createTree(Composite parent) {
Label label= new Label(parent, SWT.NONE);
label.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false));
label.setText(WorkingSetMessages.JavaWorkingSetPage_workspace_content);
fTree= new TreeViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI);
fTree.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fTree.addFilter(new AddedElementsFilter());
fTree.setUseHashlookup(true);
configureTree(fTree);
fTreeContentProvider= (ITreeContentProvider) fTree.getContentProvider();
}
private void createButtonBar(Composite parent) {
Label spacer= new Label(parent, SWT.NONE);
spacer.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
final Button addButton= new Button(parent, SWT.PUSH);
addButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
addButton.setText(WorkingSetMessages.JavaWorkingSetPage_add_button);
addButton.setEnabled(!fTree.getSelection().isEmpty());
final Button addAllButton= new Button(parent, SWT.PUSH);
addAllButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
addAllButton.setText(WorkingSetMessages.JavaWorkingSetPage_addAll_button);
addAllButton.setEnabled(fTree.getTree().getItems().length > 0);
final Button removeButton= new Button(parent, SWT.PUSH);
removeButton.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
removeButton.setText(WorkingSetMessages.JavaWorkingSetPage_remove_button);
removeButton.setEnabled(!fTable.getSelection().isEmpty());
final Button removeAllButton= new Button(parent, SWT.PUSH);
removeAllButton.setLayoutData(new GridData(SWT.CENTER, SWT.TOP, false, false));
removeAllButton.setText(WorkingSetMessages.JavaWorkingSetPage_removeAll_button);
removeAllButton.setEnabled(!fSelectedElements.isEmpty());
fTree.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
addButton.setEnabled(!event.getSelection().isEmpty());
}
});
addButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
addTreeSelection();
removeAllButton.setEnabled(true);
addAllButton.setEnabled(fTree.getTree().getItems().length > 0);
}
});
fTree.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
addTreeSelection();
removeAllButton.setEnabled(true);
addAllButton.setEnabled(fTree.getTree().getItems().length > 0);
}
});
fTable.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
removeButton.setEnabled(!event.getSelection().isEmpty());
}
});
removeButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
removeTableSelection();
addAllButton.setEnabled(true);
removeAllButton.setEnabled(!fSelectedElements.isEmpty());
}
});
fTable.addDoubleClickListener(new IDoubleClickListener() {
@Override
public void doubleClick(DoubleClickEvent event) {
removeTableSelection();
addAllButton.setEnabled(true);
removeAllButton.setEnabled(!fSelectedElements.isEmpty());
}
});
addAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
TreeItem[] items= fTree.getTree().getItems();
for (int i= 0; i < items.length; i++) {
fSelectedElements.add(items[i].getData());
}
fTable.refresh();
fTree.refresh();
addAllButton.setEnabled(false);
removeAllButton.setEnabled(true);
}
});
removeAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
fSelectedElements.clear();
fTable.refresh();
fTree.refresh();
removeAllButton.setEnabled(false);
addAllButton.setEnabled(true);
}
});
}
/**
* Moves selected elements in the tree into the table
*/
private void addTreeSelection() {
IStructuredSelection selection= (IStructuredSelection) fTree.getSelection();
fSelectedElements.addAll(selection.toList());
Object[] selectedElements= selection.toArray();
fTable.add(selectedElements);
fTree.remove(selectedElements);
fTable.setSelection(selection);
fTable.getControl().setFocus();
validateInput();
}
/**
* Moves the selected elements in the table into the tree
*/
private void removeTableSelection() {
IStructuredSelection selection= (IStructuredSelection) fTable.getSelection();
fSelectedElements.removeAll(selection.toList());
Object[] selectedElements= selection.toArray();
fTable.remove(selectedElements);
try {
fTree.getTree().setRedraw(false);
for (int i= 0; i < selectedElements.length; i++) {
fTree.refresh(fTreeContentProvider.getParent(selectedElements[i]), true);
}
} finally {
fTree.getTree().setRedraw(true);
}
fTree.setSelection(selection);
fTree.getControl().setFocus();
validateInput();
}
private void createTable(Composite parent) {
Label label= new Label(parent, SWT.WRAP);
label.setText(WorkingSetMessages.JavaWorkingSetPage_workingSet_content);
label.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));
fTable= new TableViewer(parent, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI);
GridData gd= new GridData(SWT.FILL, SWT.FILL, true, true);
fTable.getControl().setLayoutData(gd);
fTable.setUseHashlookup(true);
configureTable(fTable);
fTable.setContentProvider(new IStructuredContentProvider() {
@Override
public Object[] getElements(Object inputElement) {
return fSelectedElements.toArray();
}
@Override
public void dispose() {
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
});
}
/*
* Implements method from IWorkingSetPage
*/
@Override
public IWorkingSet getSelection() {
return fWorkingSet;
}
/*
* Implements method from IWorkingSetPage
*/
@Override
public void setSelection(IWorkingSet workingSet) {
Assert.isNotNull(workingSet, "Working set must not be null"); //$NON-NLS-1$
fWorkingSet= workingSet;
if (getContainer() != null && getShell() != null && fWorkingSetName != null) {
fFirstCheck= false;
fWorkingSetName.setText(fWorkingSet.getName());
initializeSelectedElements();
validateInput();
}
}
/*
* Implements method from IWorkingSetPage
*/
@Override
public void finish() {
String workingSetName= fWorkingSetName.getText();
HashSet<Object> elements= fSelectedElements;
if (fWorkingSet == null) {
IWorkingSetManager workingSetManager= PlatformUI.getWorkbench().getWorkingSetManager();
fWorkingSet= workingSetManager.createWorkingSet(workingSetName, elements.toArray(new IAdaptable[elements.size()]));
fWorkingSet.setId(getPageId());
} else {
// Add inaccessible resources
IAdaptable[] oldItems= fWorkingSet.getElements();
HashSet<IProject> closedProjectsToRetain= new HashSet<>(elements.size());
HashSet<IProject> closedProjectsToRemove= new HashSet<>(elements.size());
for (int i= 0; i < oldItems.length; i++) {
IResource oldResource= null;
if (oldItems[i] instanceof IResource) {
oldResource= (IResource) oldItems[i];
} else {
oldResource= oldItems[i].getAdapter(IResource.class);
}
if (oldResource != null && oldResource.isAccessible() == false) {
IProject project= oldResource.getProject();
if (oldResource.equals(project)) {
closedProjectsToRetain.add(project);
} else if (elements.contains(project)) {
elements.add(oldItems[i]);
closedProjectsToRemove.add(project);
}
}
}
closedProjectsToRemove.removeAll(closedProjectsToRetain);
elements.removeAll(closedProjectsToRemove);
fWorkingSet.setName(workingSetName);
fWorkingSet.setElements(elements.toArray(new IAdaptable[elements.size()]));
}
}
private void validateInput() {
String errorMessage= null;
String infoMessage= null;
String newText= fWorkingSetName.getText();
if (newText.equals(newText.trim()) == false)
errorMessage = WorkingSetMessages.JavaWorkingSetPage_warning_nameWhitespace;
if (newText.isEmpty()) {
if (fFirstCheck) {
setPageComplete(false);
fFirstCheck= false;
return;
} else
errorMessage= WorkingSetMessages.JavaWorkingSetPage_warning_nameMustNotBeEmpty;
}
fFirstCheck= false;
if (errorMessage == null && (fWorkingSet == null || newText.equals(fWorkingSet.getName()) == false)) {
IWorkingSet[] workingSets= PlatformUI.getWorkbench().getWorkingSetManager().getWorkingSets();
for (int i= 0; i < workingSets.length; i++) {
if (newText.equals(workingSets[i].getName())) {
errorMessage= WorkingSetMessages.JavaWorkingSetPage_warning_workingSetExists;
}
}
}
if (!hasSelectedElement())
infoMessage= WorkingSetMessages.JavaWorkingSetPage_warning_resourceMustBeChecked;
setMessage(infoMessage, INFORMATION);
setErrorMessage(errorMessage);
setPageComplete(errorMessage == null);
}
private boolean hasSelectedElement() {
return !fSelectedElements.isEmpty();
}
private void initializeSelectedElements() {
fSelectedElements.addAll(Arrays.asList(getInitialWorkingSetElements(fWorkingSet)));
}
}