blob: 735f669632ef51ab3da03488199591b8330aac22 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2017 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
*
*******************************************************************************/
package org.eclipse.dltk.internal.ui.workingsets;
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.resources.ResourcesPlugin;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.dltk.core.DLTKCore;
import org.eclipse.dltk.core.IModelElement;
import org.eclipse.dltk.core.IProjectFragment;
import org.eclipse.dltk.core.IScriptFolder;
import org.eclipse.dltk.core.IScriptModel;
import org.eclipse.dltk.core.IScriptProject;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.internal.ui.actions.SelectionConverter;
import org.eclipse.dltk.internal.ui.util.SWTUtil;
import org.eclipse.dltk.ui.DLTKPluginImages;
import org.eclipse.dltk.ui.DLTKUIPlugin;
import org.eclipse.dltk.ui.ModelElementSorter;
import org.eclipse.dltk.ui.ScriptElementImageProvider;
import org.eclipse.dltk.ui.ScriptElementLabels;
import org.eclipse.dltk.ui.viewsupport.AppearanceAwareLabelProvider;
import org.eclipse.dltk.ui.viewsupport.StyledDecoratingModelLabelProvider;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
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.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.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkingSet;
import org.eclipse.ui.IWorkingSetManager;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.IWorkingSetPage;
/**
* The Script working set page allows the user to create
* and edit a Script working set.
* <p>
* Working set elements are presented as a Script element tree.
* </p>
*
*
*/
public class ScriptWorkingSetPage extends WizardPage implements IWorkingSetPage {
final private static String PAGE_TITLE= WorkingSetMessages.ScriptWorkingSetPage_title;
final private static String PAGE_ID= "ScriptWorkingSetPage"; //$NON-NLS-1$
private Text fWorkingSetName;
private CheckboxTreeViewer fTree;
private ITreeContentProvider fTreeContentProvider;
private boolean fFirstCheck;
private IWorkingSet fWorkingSet;
/**
* Default constructor.
*/
public ScriptWorkingSetPage() {
super(PAGE_ID, PAGE_TITLE, DLTKPluginImages.DESC_WIZBAN_SCRIPT_WORKINGSET);
setDescription(WorkingSetMessages.ScriptWorkingSetPage_workingSet_description);
fFirstCheck= true;
}
/*
* @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.ScriptWorkingSetPage_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(
e -> validateInput()
);
fWorkingSetName.setFocus();
label= new Label(composite, SWT.WRAP);
label.setText(WorkingSetMessages.ScriptWorkingSetPage_workingSet_content);
gd= new GridData(GridData.GRAB_HORIZONTAL | GridData.HORIZONTAL_ALIGN_FILL | GridData.VERTICAL_ALIGN_CENTER);
label.setLayoutData(gd);
fTree= new CheckboxTreeViewer(composite, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL);
gd= new GridData(GridData.FILL_BOTH | GridData.GRAB_VERTICAL);
gd.heightHint= convertHeightInCharsToPixels(15);
fTree.getControl().setLayoutData(gd);
fTreeContentProvider= new ScriptWorkingSetPageContentProvider();
fTree.setContentProvider(fTreeContentProvider);
AppearanceAwareLabelProvider fScriptElementLabelProvider=
new AppearanceAwareLabelProvider(
AppearanceAwareLabelProvider.DEFAULT_TEXTFLAGS | ScriptElementLabels.P_COMPRESSED,
AppearanceAwareLabelProvider.DEFAULT_IMAGEFLAGS | ScriptElementImageProvider.SMALL_ICONS,
DLTKUIPlugin.getDefault().getPreferenceStore()
);
fTree.setLabelProvider(new StyledDecoratingModelLabelProvider(
fScriptElementLabelProvider));
fTree.setSorter(new ModelElementSorter());
if (DLTKCore.DEBUG) {
System.err.println("Add empty inner package filter support here..."); //$NON-NLS-1$
}
//fTree.addFilter(new EmptyInnerPackageFilter());
fTree.setUseHashlookup(true);
fTree.setInput(DLTKCore.create(ResourcesPlugin.getWorkspace().getRoot()));
fTree.addCheckStateListener(event -> handleCheckStateChange(event));
fTree.addTreeListener(new ITreeViewerListener() {
@Override
public void treeCollapsed(TreeExpansionEvent event) {
}
@Override
public void treeExpanded(TreeExpansionEvent event) {
final Object element= event.getElement();
if (fTree.getGrayed(element) == false)
BusyIndicator.showWhile(getShell().getDisplay(),
() -> setSubtreeChecked(element,
fTree.getChecked(element), false));
}
});
// Add select / deselect all buttons for bug 46669
Composite buttonComposite = new Composite(composite, SWT.NONE);
GridLayout layout= new GridLayout(2, false);
layout.marginWidth= 0; layout.marginHeight= 0;
buttonComposite.setLayout(layout);
buttonComposite.setLayoutData(new GridData(GridData.HORIZONTAL_ALIGN_FILL));
Button selectAllButton = new Button(buttonComposite, SWT.PUSH);
selectAllButton.setText(WorkingSetMessages.ScriptWorkingSetPage_selectAll_label);
selectAllButton.setToolTipText(WorkingSetMessages.ScriptWorkingSetPage_selectAll_toolTip);
selectAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
fTree.setCheckedElements(fTreeContentProvider.getElements(fTree.getInput()));
validateInput();
}
});
selectAllButton.setLayoutData(new GridData());
SWTUtil.setButtonDimensionHint(selectAllButton);
Button deselectAllButton = new Button(buttonComposite, SWT.PUSH);
deselectAllButton.setText(WorkingSetMessages.ScriptWorkingSetPage_deselectAll_label);
deselectAllButton.setToolTipText(WorkingSetMessages.ScriptWorkingSetPage_deselectAll_toolTip);
deselectAllButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent selectionEvent) {
fTree.setCheckedElements(new Object[0]);
validateInput();
}
});
deselectAllButton.setLayoutData(new GridData());
SWTUtil.setButtonDimensionHint(deselectAllButton);
if (fWorkingSet != null)
fWorkingSetName.setText(fWorkingSet.getName());
initializeCheckedState();
validateInput();
Dialog.applyDialogFont(composite);
// Set help for the page
if (DLTKCore.DEBUG) {
System.err.println("Add help support here..."); //$NON-NLS-1$
}
//ScriptUIHelp.setHelp(fTree, IScriptHelpContextIds.Script_WORKING_SET_PAGE);
}
/*
* 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());
initializeCheckedState();
validateInput();
}
}
/*
* Implements method from IWorkingSetPage
*/
@Override
public void finish() {
String workingSetName= fWorkingSetName.getText();
ArrayList<IAdaptable> elements = new ArrayList<IAdaptable>(10);
findCheckedElements(elements, fTree.getInput());
if (fWorkingSet == null) {
IWorkingSetManager workingSetManager= PlatformUI.getWorkbench().getWorkingSetManager();
fWorkingSet = workingSetManager.createWorkingSet(workingSetName,
elements.toArray(new IAdaptable[elements.size()]));
} else {
// Add inaccessible resources
IAdaptable[] oldItems= fWorkingSet.getElements();
ArrayList closedWithChildren= new ArrayList(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 (elements.contains(project) || closedWithChildren.contains(project)) {
elements.add(oldItems[i]);
elements.remove(project);
closedWithChildren.add(project);
}
}
}
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.ScriptWorkingSetPage_warning_nameWhitespace;
if (newText.equals("")) { //$NON-NLS-1$
if (fFirstCheck) {
setPageComplete(false);
fFirstCheck= false;
return;
}
else
errorMessage= WorkingSetMessages.ScriptWorkingSetPage_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.ScriptWorkingSetPage_warning_workingSetExists;
}
}
}
if (!hasCheckedElement())
infoMessage= WorkingSetMessages.ScriptWorkingSetPage_warning_resourceMustBeChecked;
setMessage(infoMessage, INFORMATION);
setErrorMessage(errorMessage);
setPageComplete(errorMessage == null);
}
private boolean hasCheckedElement() {
TreeItem[] items= fTree.getTree().getItems();
for (int i= 0; i < items.length; i++) {
if (items[i].getChecked())
return true;
}
return false;
}
private void findCheckedElements(List checkedResources, Object parent) {
Object[] children= fTreeContentProvider.getChildren(parent);
for (int i= 0; i < children.length; i++) {
if (fTree.getGrayed(children[i]))
findCheckedElements(checkedResources, children[i]);
else if (fTree.getChecked(children[i]))
checkedResources.add(children[i]);
}
}
void handleCheckStateChange(final CheckStateChangedEvent event) {
BusyIndicator.showWhile(getShell().getDisplay(), () -> {
IAdaptable element = (IAdaptable) event.getElement();
boolean state = event.getChecked();
fTree.setGrayed(element, false);
if (isExpandable(element))
setSubtreeChecked(element, state, state); // only check subtree
// if state is set
// to true
updateParentState(element, state);
validateInput();
});
}
private void setSubtreeChecked(Object parent, boolean state, boolean checkExpandedState) {
if (!(parent instanceof IAdaptable))
return;
IContainer container = ((IAdaptable) parent)
.getAdapter(IContainer.class);
if ((!fTree.getExpandedState(parent) && checkExpandedState) || (container != null && !container.isAccessible()))
return;
Object[] children= fTreeContentProvider.getChildren(parent);
for (int i= children.length - 1; i >= 0; i--) {
Object element= children[i];
if (state) {
fTree.setChecked(element, true);
fTree.setGrayed(element, false);
}
else
fTree.setGrayChecked(element, false);
if (isExpandable(element))
setSubtreeChecked(element, state, true);
}
}
private void updateParentState(Object child, boolean baseChildState) {
if (child == null)
return;
if (child instanceof IAdaptable) {
IResource resource = ((IAdaptable) child)
.getAdapter(IResource.class);
if (resource != null && !resource.isAccessible())
return;
}
Object parent= fTreeContentProvider.getParent(child);
if (parent == null)
return;
boolean allSameState= true;
Object[] children= null;
children= fTreeContentProvider.getChildren(parent);
for (int i= children.length -1; i >= 0; i--) {
if (fTree.getChecked(children[i]) != baseChildState || fTree.getGrayed(children[i])) {
allSameState= false;
break;
}
}
fTree.setGrayed(parent, !allSameState);
fTree.setChecked(parent, !allSameState || baseChildState);
updateParentState(parent, baseChildState);
}
private void initializeCheckedState() {
BusyIndicator.showWhile(getShell().getDisplay(), () -> {
Object[] elements;
if (fWorkingSet == null) {
// Use current part's selection for initialization
IWorkbenchPage page = DLTKUIPlugin.getActivePage();
if (page == null)
return;
IWorkbenchPart part = DLTKUIPlugin.getActivePage()
.getActivePart();
if (part == null)
return;
try {
elements = SelectionConverter.getStructuredSelection(part)
.toArray();
for (int i1 = 0; i1 < elements.length; i1++) {
if (elements[i1] instanceof IResource) {
IModelElement je = ((IResource) elements[i1])
.getAdapter(IModelElement.class);
if (je != null && je.exists()
&& je.getScriptProject().isOnBuildpath(
(IResource) elements[i1]))
elements[i1] = je;
}
}
} catch (ModelException e) {
return;
}
} else
elements = fWorkingSet.getElements();
// Use closed project for elements in closed project
for (int i2 = 0; i2 < elements.length; i2++) {
Object element1 = elements[i2];
if (element1 instanceof IResource) {
IProject project = ((IResource) element1).getProject();
if (!project.isAccessible())
elements[i2] = project;
}
if (element1 instanceof IModelElement) {
IScriptProject jProject = ((IModelElement) element1)
.getScriptProject();
if (jProject != null
&& !jProject.getProject().isAccessible())
elements[i2] = jProject.getProject();
}
}
fTree.setCheckedElements(elements);
for (int i3 = 0; i3 < elements.length; i3++) {
Object element2 = elements[i3];
if (isExpandable(element2))
setSubtreeChecked(element2, true, true);
updateParentState(element2, true);
}
});
}
private boolean isExpandable(Object element) {
return (
element instanceof IScriptProject
||
element instanceof IProjectFragment
||
element instanceof IScriptFolder
||
element instanceof IScriptModel
||
element instanceof IContainer);
}
}