blob: 79419b4db8373c65c7ca42c85c4ad8ac70e506bf [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2008 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.ltk.internal.ui.refactoring;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.ltk.core.refactoring.GroupCategory;
class ChangeElementTreeViewer extends CheckboxTreeViewer {
private static class GroupCategoryFilter extends ViewerFilter {
private List<GroupCategory> fGroupCategories;
public void setGroupCategory(List<GroupCategory> groupCategories) {
fGroupCategories= groupCategories;
}
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
if (fGroupCategories == null)
return true;
return ((PreviewNode)element).hasOneGroupCategory(fGroupCategories);
}
}
private static class DerivedFilter extends ViewerFilter {
@Override
public boolean select(Viewer viewer, Object parentElement, Object element) {
return ! ((PreviewNode) element).hasDerived();
}
}
private static final DerivedFilter DERIVED_FILTER= new DerivedFilter();
// Workaround for http://bugs.eclipse.org/bugs/show_bug.cgi?id=9390
private List<Item> fDeferredTreeItemUpdates;
public ChangeElementTreeViewer(Composite parentComposite) {
super(parentComposite, SWT.NONE);
addFilter(new GroupCategoryFilter());
addCheckStateListener(new ICheckStateListener() {
@Override
public void checkStateChanged(CheckStateChangedEvent event){
PreviewNode element= (PreviewNode)event.getElement();
boolean checked= event.getChecked();
element.setEnabled(checked);
setSubtreeChecked(element, checked);
setSubtreeGrayed(element, false);
PreviewNode parent= element.getParent();
while(parent != null) {
int active= parent.getActive();
parent.setEnabledShallow(active == PreviewNode.PARTLY_ACTIVE || active == PreviewNode.ACTIVE);
boolean grayed= (active == PreviewNode.PARTLY_ACTIVE);
setChecked(parent, checked ? true : grayed);
setGrayed(parent, grayed);
parent= parent.getParent();
}
}
});
}
public void setGroupCategory(List<GroupCategory> groupCategories) {
((GroupCategoryFilter)(getFilters()[0])).setGroupCategory(groupCategories);
refresh();
}
public void setHideDerived(boolean hide) {
if (hide) {
addFilter(DERIVED_FILTER);
} else {
removeFilter(DERIVED_FILTER);
}
}
@Override
public void refresh() {
try {
fDeferredTreeItemUpdates= new ArrayList<>();
super.refresh();
processDeferredTreeItemUpdates();
} finally {
fDeferredTreeItemUpdates= null;
}
}
@Override
protected void handleInvalidSelection(ISelection invalidSelection, ISelection newSelection) {
PreviewNode next= getLeaf((PreviewNode)getInput(), true);
if (next != null) {
newSelection= new StructuredSelection(next);
setSelection(newSelection);
}
super.handleInvalidSelection(invalidSelection, newSelection);
}
@Override
protected void inputChanged(Object input, Object oldInput) {
try {
fDeferredTreeItemUpdates= new ArrayList<>();
super.inputChanged(input, oldInput);
processDeferredTreeItemUpdates();
} finally {
fDeferredTreeItemUpdates= null;
}
}
@Override
protected void doUpdateItem(Item item, Object element) {
super.doUpdateItem(item, element);
if (fDeferredTreeItemUpdates == null) {
applyCheckedState((TreeItem)item, (PreviewNode)element);
} else {
fDeferredTreeItemUpdates.add(item);
}
}
private void processDeferredTreeItemUpdates() {
for (Iterator<Item> iter= fDeferredTreeItemUpdates.iterator(); iter.hasNext();) {
TreeItem item= (TreeItem)iter.next();
applyCheckedState(item, (PreviewNode)item.getData());
}
}
private void applyCheckedState(TreeItem item, PreviewNode ce) {
int state= ce.getActive();
boolean checked= state == PreviewNode.INACTIVE ? false : true;
item.setChecked(checked);
boolean grayed= state == PreviewNode.PARTLY_ACTIVE ? true : false;
item.setGrayed(grayed);
}
protected void revealNext() {
revealElement(true);
}
protected void revealPrevious() {
revealElement(false);
}
private void setSubtreeGrayed(Object element, boolean grayed) {
Widget widget= findItem(element);
if (widget instanceof TreeItem) {
TreeItem item= (TreeItem)widget;
if (item.getGrayed() != grayed) {
item.setGrayed(grayed);
grayChildren(getChildren(item), grayed);
}
}
}
private void grayChildren(Item[] items, boolean grayed) {
for (Item element : items) {
if (element instanceof TreeItem) {
TreeItem item= (TreeItem)element;
if (item.getGrayed() != grayed) {
item.setGrayed(grayed);
grayChildren(getChildren(item), grayed);
}
}
}
}
private void revealElement(boolean next) {
PreviewNode current= (PreviewNode)getInput();
IStructuredSelection selection= (IStructuredSelection)getSelection();
if (!selection.isEmpty())
current= (PreviewNode)selection.iterator().next();
PreviewNode candidate= getLeaf(current, next);
if (candidate == null) {
candidate= getElement(current, next);
if (candidate != null) {
PreviewNode leaf= getLeaf(candidate, next);
if (leaf != null)
candidate= leaf;
}
}
if (candidate != null)
setSelection(new StructuredSelection(candidate), true);
else
getControl().getDisplay().beep();
}
private PreviewNode getLeaf(PreviewNode element, boolean first) {
PreviewNode result= null;
PreviewNode[] children= getSortedChildrenAsPreviewNodes(element);
while(children != null && children.length > 0) {
result= children[first ? 0 : children.length - 1];
children= getSortedChildrenAsPreviewNodes(result);
}
return result;
}
private PreviewNode getElement(PreviewNode element, boolean next) {
while(true) {
PreviewNode parent= element.getParent();
if (parent == null)
return null;
PreviewNode candidate= getSibling(
getSortedChildrenAsPreviewNodes(parent),
element, next);
if (candidate != null)
return candidate;
element= parent;
}
}
private PreviewNode getSibling(PreviewNode[] children, PreviewNode element, boolean next) {
for (int i= 0; i < children.length; i++) {
if (children[i] == element) {
if (next)
if (i < children.length - 1)
return children[i + 1];
else
return null;
else
if (i > 0)
return children[i - 1];
else
return null;
}
}
return null;
}
private PreviewNode[] getSortedChildrenAsPreviewNodes(PreviewNode parent) {
Object[] sorted= getSortedChildren(parent);
PreviewNode[] result= new PreviewNode[sorted.length];
for (int i= 0; i < result.length; i++) {
result[i]= (PreviewNode)sorted[i];
}
return result;
}
}