blob: 8886c18d8647ab84c34834f6c5244761ee0c7869 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2015 Wind River Systems 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:
* Wind River Systems - initial API and implementation
* IBM Corporation - ongoing bug fixes and enhancements
*******************************************************************************/
package org.eclipse.debug.internal.ui.viewers.model;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelChangedListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IPresentationContext;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IStateUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.IViewerUpdateListener;
import org.eclipse.debug.internal.ui.viewers.model.provisional.ModelDelta;
import org.eclipse.debug.internal.ui.viewers.model.provisional.TreeModelViewer;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerLabel;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
/**
* Specialized tree viewer which displays only sub-tree of a full model.
*
* @since 3.5
*/
public class SubTreeModelViewer extends TreeModelViewer {
/**
* The tree path in the model to the root element of this viewer.
*/
private TreePath fRootPath = TreePath.EMPTY;
/**
* Viewer delegate that content and label providers refer to for viewer data.
*/
private DelegatingTreeModelViewer fDelegatingViewer;
/**
* @return Returns the root element's model tree path.
*/
public TreePath getRootPath() {
return fRootPath;
}
public SubTreeModelViewer(Composite parent, int style, IPresentationContext context) {
super(parent, style, context);
}
/**
* Sets the viewer's input and root element's path
*
* @param input New viewer input.
* @param rootPath New root element path.
*/
public void setInput(Object input, TreePath rootPath) {
fRootPath = rootPath;
super.setInput(input);
}
/**
* A proxy for the sub tree viewer which is given to the content and
* label providers. It translates the sub-tree paths in the viewer to the
* full model paths that the providers expect.
*/
public class DelegatingTreeModelViewer extends Viewer
implements IInternalTreeModelViewer
{
@Override
public void reveal(TreePath path, int index) {
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.reveal(createSubPath(path), index);
}
}
@Override
public void replace(Object parentOrTreePath, int index, Object element) {
if (parentOrTreePath instanceof TreePath) {
TreePath path = (TreePath)parentOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.replace(createSubPath(path), index, element);
}
} else {
SubTreeModelViewer.this.replace(parentOrTreePath, index, element);
}
}
@Override
public void setChildCount(Object elementOrTreePath, int count) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.setChildCount(createSubPath(path), count);
}
} else {
SubTreeModelViewer.this.setChildCount(elementOrTreePath, count);
}
}
@Override
public void setHasChildren(Object elementOrTreePath, boolean hasChildren) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.setHasChildren(createSubPath(path), hasChildren);
}
} else {
SubTreeModelViewer.this.setHasChildren(elementOrTreePath, hasChildren);
}
}
@Override
public void autoExpand(TreePath elementPath) {
// not supported
}
@Override
public void setExpandedState(Object elementOrTreePath, boolean expanded) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.setExpandedState(createSubPath(path), expanded);
}
} else {
SubTreeModelViewer.this.setExpandedState(elementOrTreePath, expanded);
}
}
@Override
public void expandToLevel(Object elementOrTreePath, int level) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.expandToLevel(createSubPath(path), level);
}
} else {
SubTreeModelViewer.this.expandToLevel(elementOrTreePath, level);
}
}
@Override
public void remove(Object elementOrTreePath) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.remove(createSubPath(path));
}
} else {
SubTreeModelViewer.this.remove(elementOrTreePath);
}
}
@Override
public void remove(Object parentOrTreePath, final int index) {
if (parentOrTreePath instanceof TreePath) {
TreePath path = (TreePath)parentOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.remove(createSubPath(path), index);
}
} else {
SubTreeModelViewer.this.remove(parentOrTreePath, index);
}
}
@Override
public void insert(Object parentOrTreePath, Object element, int position) {
if (parentOrTreePath instanceof TreePath) {
TreePath path = (TreePath)parentOrTreePath;
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.insert(createSubPath(path), element, position);
}
} else {
SubTreeModelViewer.this.insert(parentOrTreePath, element, position);
}
}
@Override
public boolean getExpandedState(Object elementOrTreePath) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
return SubTreeModelViewer.this.getExpandedState(createSubPath(path));
}
} else {
return SubTreeModelViewer.this.getExpandedState(elementOrTreePath);
}
return false;
}
@Override
public int getChildCount(TreePath path) {
if (path.startsWith(fRootPath, null)) {
return SubTreeModelViewer.this.getChildCount(createSubPath(path));
}
return -1;
}
@Override
public boolean getHasChildren(Object elementOrTreePath) {
if (elementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)elementOrTreePath;
if (path.startsWith(fRootPath, null)) {
return SubTreeModelViewer.this.getHasChildren(createSubPath(path));
}
} else {
return SubTreeModelViewer.this.getHasChildren(elementOrTreePath);
}
return false;
}
@Override
public Object getChildElement(TreePath path, int index) {
if (path.startsWith(fRootPath, null)) {
return SubTreeModelViewer.this.getChildElement(createSubPath(path), index);
}
return null;
}
@Override
public TreePath getTopElementPath() {
return createFullPath(SubTreeModelViewer.this.getTopElementPath());
}
@Override
public int findElementIndex(TreePath parentPath, Object element) {
if (parentPath.startsWith(fRootPath, null)) {
return SubTreeModelViewer.this.findElementIndex(createSubPath(parentPath), element);
}
return -1;
}
@Override
public boolean getElementChildrenRealized(TreePath parentPath) {
if (parentPath.startsWith(fRootPath, null)) {
return SubTreeModelViewer.this.getElementChildrenRealized(createSubPath(parentPath));
}
return true;
}
@Override
public void setElementData(TreePath path, int numColumns, String[] labels, ImageDescriptor[] images, FontData[] fontDatas, RGB[] foregrounds, RGB[] backgrounds) {
if (path.startsWith(fRootPath, null)) {
SubTreeModelViewer.this.setElementData(createSubPath(path), numColumns, labels, images, fontDatas, foregrounds, backgrounds);
}
}
@Override
public Control getControl() {
return SubTreeModelViewer.this.getControl();
}
@Override
public Object getInput() {
return SubTreeModelViewer.this.getInput();
}
@Override
public ISelection getSelection() {
return SubTreeModelViewer.this.getSelection();
}
@Override
public void refresh() {
SubTreeModelViewer.this.refresh();
}
@Override
public void setInput(Object input) {
SubTreeModelViewer.this.setInput(input);
}
@Override
public void setSelection(ISelection selection, boolean reveal) {
SubTreeModelViewer.this.setSelection(selection, reveal);
}
@Override
public String[] getVisibleColumns() {
return SubTreeModelViewer.this.getVisibleColumns();
}
@Override
public void addLabelUpdateListener(ILabelUpdateListener listener) {
SubTreeModelViewer.this.addLabelUpdateListener(listener);
}
@Override
public void addModelChangedListener(IModelChangedListener listener) {
SubTreeModelViewer.this.addModelChangedListener(listener);
}
@Override
public void addStateUpdateListener(IStateUpdateListener listener) {
SubTreeModelViewer.this.addStateUpdateListener(listener);
}
@Override
public void addViewerUpdateListener(IViewerUpdateListener listener) {
SubTreeModelViewer.this.addViewerUpdateListener(listener);
}
@Override
public int getAutoExpandLevel() {
return SubTreeModelViewer.this.getAutoExpandLevel();
}
@Override
public Display getDisplay() {
return SubTreeModelViewer.this.getDisplay();
}
@Override
public ViewerLabel getElementLabel(TreePath path, String columnId) {
return SubTreeModelViewer.this.getElementLabel(path, columnId);
}
@Override
public IPresentationContext getPresentationContext() {
return SubTreeModelViewer.this.getPresentationContext();
}
@Override
public void removeLabelUpdateListener(ILabelUpdateListener listener) {
SubTreeModelViewer.this.removeLabelUpdateListener(listener);
}
@Override
public void removeModelChangedListener(IModelChangedListener listener) {
SubTreeModelViewer.this.removeModelChangedListener(listener);
}
@Override
public void removeStateUpdateListener(IStateUpdateListener listener) {
SubTreeModelViewer.this.removeStateUpdateListener(listener);
}
@Override
public void removeViewerUpdateListener(IViewerUpdateListener listener) {
SubTreeModelViewer.this.removeViewerUpdateListener(listener);
}
@Override
public boolean saveElementState(TreePath path, ModelDelta delta, int deltaFlags) {
return SubTreeModelViewer.this.saveElementState(path, delta, deltaFlags);
}
@Override
public void setAutoExpandLevel(int level) {
SubTreeModelViewer.this.setAutoExpandLevel(level);
}
@Override
public void setSelection(ISelection selection, boolean reveal, boolean force) {
SubTreeModelViewer.this.setSelection(selection, reveal, force);
}
@Override
public boolean trySelection(ISelection selection, boolean reveal, boolean force) {
return SubTreeModelViewer.this.trySelection(selection, reveal, force);
}
@Override
public void updateViewer(IModelDelta delta) {
SubTreeModelViewer.this.updateViewer(delta);
}
@Override
public ViewerFilter[] getFilters() {
return SubTreeModelViewer.this.getFilters();
}
@Override
public void addFilter(ViewerFilter filter) {
SubTreeModelViewer.this.addFilter(filter);
}
@Override
public void setFilters(ViewerFilter... filters) {
SubTreeModelViewer.this.setFilters(filters);
}
@Override
public boolean overrideSelection(ISelection current, ISelection candidate) {
return SubTreeModelViewer.this.overrideSelection(current, candidate);
}
@Override
public void refresh(Object element) {
SubTreeModelViewer.this.refresh(element);
}
@Override
public void update(Object element) {
SubTreeModelViewer.this.update(element);
}
@Override
public void clearSelectionQuiet() {
SubTreeModelViewer.this.clearSelectionQuiet();
}
@Override
public TreePath[] getElementPaths(Object element) {
TreePath[] subViewerPaths = SubTreeModelViewer.this.getElementPaths(element);
TreePath[] retVal = new TreePath[subViewerPaths.length];
for (int i = 0; i < subViewerPaths.length; i++) {
retVal[i] = createFullPath(subViewerPaths[i]);
}
return retVal;
}
@Override
public boolean getElementChecked(TreePath path) {
return SubTreeModelViewer.this.getElementChecked(createSubPath(path));
}
@Override
public boolean getElementGrayed(TreePath path) {
return SubTreeModelViewer.this.getElementGrayed(createSubPath(path));
}
@Override
public void setElementChecked(TreePath path, boolean checked, boolean grayed) {
SubTreeModelViewer.this.setElementChecked(createSubPath(path), checked, grayed);
}
}
/**
* Delegating content provider. It translates all the calls to the
* underlying content provider to use full model tree paths.
*/
private class SubTreeModelContentProvider implements ITreeModelContentProvider {
private TreeModelContentProvider fBaseProvider;
public SubTreeModelContentProvider() {
fBaseProvider = new TreeModelContentProvider();
}
@Override
public void updateHasChildren(TreePath path) {
fBaseProvider.updateHasChildren(createFullPath(path));
}
@Override
public void updateChildCount(TreePath path, int currentChildCount) {
fBaseProvider.updateChildCount(createFullPath(path), currentChildCount);
}
@Override
public void updateElement(TreePath parentPath, int viewIndex) {
fBaseProvider.updateElement(createFullPath(parentPath), viewIndex);
}
@Override
public int viewToModelCount(TreePath parentPath, int count) {
return fBaseProvider.viewToModelCount(createFullPath(parentPath), count);
}
@Override
public int viewToModelIndex(TreePath parentPath, int index) {
return fBaseProvider.viewToModelIndex(createFullPath(parentPath), index);
}
@Override
public void addModelChangedListener(IModelChangedListener listener) {
fBaseProvider.addModelChangedListener(listener);
}
@Override
public void preserveState(TreePath subPath) {
fBaseProvider.preserveState(createFullPath(subPath));
}
@Override
public void addStateUpdateListener(IStateUpdateListener listener) {
fBaseProvider.addStateUpdateListener(listener);
}
@Override
public void addViewerUpdateListener(IViewerUpdateListener listener) {
fBaseProvider.addViewerUpdateListener(listener);
}
@Override
public int getModelDeltaMask() {
return fBaseProvider.getModelDeltaMask();
}
@Override
public int modelToViewChildCount(TreePath parentPath, int count) {
return fBaseProvider.modelToViewChildCount(createFullPath(parentPath), count);
}
@Override
public int modelToViewIndex(TreePath parentPath, int index) {
return fBaseProvider.modelToViewIndex(createFullPath(parentPath), index);
}
@Override
public void removeModelChangedListener(IModelChangedListener listener) {
fBaseProvider.removeModelChangedListener(listener);
}
@Override
public void removeStateUpdateListener(IStateUpdateListener listener) {
fBaseProvider.removeStateUpdateListener(listener);
}
@Override
public void removeViewerUpdateListener(IViewerUpdateListener listener) {
fBaseProvider.removeViewerUpdateListener(listener);
}
@Override
public void setModelDeltaMask(int mask) {
fBaseProvider.setModelDeltaMask(mask);
}
@Override
public boolean areTreeModelViewerFiltersApplicable(Object parentElement) {
return fBaseProvider.areTreeModelViewerFiltersApplicable(parentElement);
}
@Override
public boolean shouldFilter(Object parentElementOrTreePath, Object element) {
if (parentElementOrTreePath instanceof TreePath) {
TreePath path = (TreePath)parentElementOrTreePath;
return fBaseProvider.shouldFilter(createFullPath(path), element);
} else {
return fBaseProvider.shouldFilter(parentElementOrTreePath, element);
}
}
@Override
public void unmapPath(TreePath path) {
fBaseProvider.unmapPath(createFullPath(path));
}
@Override
public void updateModel(IModelDelta delta, int mask) {
fBaseProvider.updateModel(delta, mask);
}
@Override
public TreePath[] getParents(Object element) {
// Not used
return null;
}
@Override
public void cancelRestore(TreePath path, int flags) {
fBaseProvider.cancelRestore(createFullPath(path), flags);
}
@Override
public void dispose() {
fBaseProvider.dispose();
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
fBaseProvider.inputChanged(fDelegatingViewer, oldInput, newInput);
}
@Override
public void postInputChanged(IInternalTreeModelViewer viewer,
Object oldInput, Object newInput) {
fBaseProvider.postInputChanged(viewer, oldInput, newInput);
}
@Override
public boolean setChecked(TreePath path, boolean checked) {
return fBaseProvider.setChecked(createFullPath(path), checked);
}
}
/**
* Delegating label provider. It translates all the calls to the
* underlying label provider to use full model tree paths.
*/
private class SubTreeModelLabelProvider extends ColumnLabelProvider
implements ITreeModelLabelProvider
{
private TreeModelLabelProvider fBaseProvider;
public SubTreeModelLabelProvider(IInternalTreeModelViewer viewer) {
fBaseProvider = new TreeModelLabelProvider(viewer);
}
@Override
public boolean update(TreePath elementPath) {
return fBaseProvider.update( createFullPath(elementPath) );
}
@Override
public void addLabelUpdateListener(ILabelUpdateListener listener) {
fBaseProvider.addLabelUpdateListener(listener);
}
@Override
public Color getColor(RGB rgb) {
return fBaseProvider.getColor(rgb);
}
@Override
public Font getFont(FontData fontData) {
return fBaseProvider.getFont(fontData);
}
@Override
public Image getImage(ImageDescriptor descriptor) {
return fBaseProvider.getImage(descriptor);
}
@Override
public void removeLabelUpdateListener(ILabelUpdateListener listener) {
fBaseProvider.removeLabelUpdateListener(listener);
}
@Override
public void addListener(ILabelProviderListener listener) {
fBaseProvider.addListener(listener);
}
@Override
public void dispose() {
fBaseProvider.dispose();
super.dispose();
}
@Override
public boolean isLabelProperty(Object element, String property) {
return fBaseProvider.isLabelProperty(element, property);
}
@Override
public void removeListener(ILabelProviderListener listener) {
fBaseProvider.removeListener(listener);
}
}
private TreePath createFullPath(TreePath subPath) {
if (fRootPath == null) {
return TreePath.EMPTY;
}
Object[] segments = new Object[fRootPath.getSegmentCount() + subPath.getSegmentCount()];
for (int i = 0; i < fRootPath.getSegmentCount(); i++) {
segments[i] = fRootPath.getSegment(i);
}
for (int i = 0; i < subPath.getSegmentCount(); i++) {
segments[i + fRootPath.getSegmentCount()] = subPath.getSegment(i);
}
return new TreePath(segments);
}
private TreePath createSubPath(TreePath fullPath) {
if (fRootPath == null) {
return TreePath.EMPTY;
}
if (fullPath.getSegmentCount() <= fRootPath.getSegmentCount()) {
return TreePath.EMPTY;
}
Object[] segments = new Object[fullPath.getSegmentCount() - fRootPath.getSegmentCount()];
for (int i = 0; i < segments.length; i++) {
segments[i] = fullPath.getSegment(i + fRootPath.getSegmentCount());
}
return new TreePath(segments);
}
private DelegatingTreeModelViewer getDelegatingViewer() {
if (fDelegatingViewer == null) {
fDelegatingViewer = new DelegatingTreeModelViewer();
}
return fDelegatingViewer;
}
@Override
protected ITreeModelContentProvider createContentProvider() {
return new SubTreeModelContentProvider();
}
@Override
protected ITreeModelLabelProvider createLabelProvider() {
return new SubTreeModelLabelProvider(getDelegatingViewer());
}
}