blob: 3de7be9adb7a180089207bcd70c78fc2afbb4003 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2006 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
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.navigator;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.viewers.DecoratingLabelProvider;
import org.eclipse.jface.viewers.IBaseLabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProviderChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Widget;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.internal.navigator.ContributorTrackingSet;
import org.eclipse.ui.internal.navigator.NavigatorContentService;
import org.eclipse.ui.internal.navigator.NavigatorPipelineService;
/**
*
* Provides the Tree Viewer for the Common Navigator. Content and labels are
* provided by an instance of {@link INavigatorContentService}  which uses
* the ID supplied in the constructor
* {@link CommonViewer#CommonViewer(String, Composite, int)} or through
* {@link NavigatorContentServiceFactory#createContentService(String, org.eclipse.jface.viewers.StructuredViewer)}.
*
* <p>
* Clients may extend this class.
* </p>
*
* <p>
* Note that as of 3.2.1 and 3.3, the common viewer caches its selection.
* Clients must not set the selection of the viewer's tree control directly.
* </p>
*
* @since 3.2
*/
public class CommonViewer extends TreeViewer {
private final NavigatorContentService contentService;
private ISelection cachedSelection;
/**
* <p>
* Constructs the Tree Viewer for the Common Navigator and the corresponding
* NavigatorContentService. The NavigatorContentService will provide the
* Content Provider and Label Provider -- these need not be supplied by
* clients.
* <p>
* For the valid bits to supply in the style mask (aStyle), see
* documentation provided by {@link TreeViewer}.
* </p>
*
* @param aViewerId
* An id tied to the extensions that is used to focus specific
* content to a particular instance of the Common Navigator
* @param aParent
* A Composite parent to contain the actual SWT widget
* @param aStyle
* A style mask that will be used to create the TreeViewer
* Composite.
*/
public CommonViewer(String aViewerId, Composite aParent, int aStyle) {
super(aParent, aStyle);
contentService = new NavigatorContentService(aViewerId, this);
init();
}
/**
* <p>
* Initializes the content provider, label provider, and drag and drop
* support. Should not be called by clients -- this method is invoked when
* the constructor is invoked.
* </p>
*/
protected void init() {
setUseHashlookup(true);
setContentProvider(contentService.createCommonContentProvider());
DecoratingLabelProvider decoratingProvider = new DecoratingLabelProvider(
contentService.createCommonLabelProvider(), PlatformUI
.getWorkbench().getDecoratorManager()
.getLabelDecorator());
setLabelProvider(decoratingProvider);
initDragAndDrop();
}
protected void removeWithoutRefresh(Object[] elements) {
super.remove(elements);
}
/**
* <p>
* Adds DND support to the Navigator. Uses hooks into the extensible
* framework for DND.
* </p>
* <p>
* By default, the following Transfer types are supported:
* <ul>
* <li>LocalSelectionTransfer.getInstance(),
* <li>PluginTransfer.getInstance()
* </ul>
* </p>
*
* @see CommonDragAdapter
* @see CommonDropAdapter
*/
protected void initDragAndDrop() {
/* Handle Drag and Drop */
int operations = DND.DROP_COPY | DND.DROP_MOVE;
CommonDragAdapter dragAdapter = new CommonDragAdapter(contentService,
this);
addDragSupport(operations, dragAdapter.getSupportedDragTransfers(),
dragAdapter);
CommonDropAdapter dropAdapter = new CommonDropAdapter(contentService,
this);
addDropSupport(operations, dropAdapter.getSupportedDropTransfers(),
dropAdapter);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.AbstractTreeViewer#createTreeItem(org.eclipse.swt.widgets.Widget,
* java.lang.Object, int)
*/
protected void createTreeItem(Widget parent, final Object element, int index) {
try {
super.createTreeItem(parent, element, index);
} catch (Exception ex) {
ex.printStackTrace();
} catch (Error e) {
e.printStackTrace();
}
}
/*
* @see ContentViewer#handleLabelProviderChanged(LabelProviderChangedEvent)
*/
protected void handleLabelProviderChanged(LabelProviderChangedEvent event) {
Object[] changed = event.getElements();
if (changed != null) {
List others = Arrays.asList(changed);
for (Iterator iter = others.iterator(); iter.hasNext();) {
if(iter.next() == null)
iter.remove();
}
if (others.isEmpty()) {
return;
}
event = new LabelProviderChangedEvent((IBaseLabelProvider) event
.getSource(), others.toArray());
}
super.handleLabelProviderChanged(event);
}
protected void handleDispose(DisposeEvent event) {
dispose();
super.handleDispose(event);
}
/**
* <p>
* Disposes of the NavigatorContentService, which will dispose the Content
* and Label providers.
* </p>
*/
public void dispose() {
if (contentService != null) {
contentService.dispose();
}
clearSelectionCache();
}
/**
* Sets this viewer's sorter and triggers refiltering and resorting of this
* viewer's element. Passing <code>null</code> turns sorting off.
*
* @param sorter
* a viewer sorter, or <code>null</code> if none
*/
public void setSorter(ViewerSorter sorter) {
if (sorter != null && sorter instanceof CommonViewerSorter) {
((CommonViewerSorter) sorter).setContentService(contentService);
}
super.setSorter(sorter);
}
/**
* <p>
* The {@link INavigatorContentService}provides the hook into the framework
* to provide content from the various extensions.
* </p>
*
* @return The {@link INavigatorContentService}that was created when the
* viewer was created.
*/
public INavigatorContentService getNavigatorContentService() {
return contentService;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.AbstractTreeViewer#add(java.lang.Object,
* java.lang.Object[])
*/
public void add(Object parentElement, Object[] childElements) {
// TODO Intercept ADD for the pipeline service.
NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
.getPipelineService();
PipelinedShapeModification modification = new PipelinedShapeModification(
parentElement, new ContributorTrackingSet(contentService,
childElements));
pipeDream.interceptAdd(modification);
Object parent = (parentElement == getInput()) ? getInput()
: modification.getParent();
super.add(parent, modification.getChildren().toArray());
}
/**
* <p>
* Removals are handled by refreshing the parents of each of the given
* elements. The parents are determined via calls ot the contentProvider.
* </p>
*
* @see org.eclipse.jface.viewers.AbstractTreeViewer#remove(java.lang.Object[])
*/
public void remove(Object[] elements) {
// TODO Intercept REMOVE for the pipeline service.
NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
.getPipelineService();
PipelinedShapeModification modification = new PipelinedShapeModification(
null, new ContributorTrackingSet(contentService, elements));
pipeDream.interceptRemove(modification);
super.remove(modification.getChildren().toArray());
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#refresh(java.lang.Object,
* boolean)
*/
public void refresh(Object element, boolean updateLabels) {
if(element != getInput()) {
INavigatorPipelineService pipeDream = contentService
.getPipelineService();
PipelinedViewerUpdate update = new PipelinedViewerUpdate();
update.getRefreshTargets().add(element);
update.setUpdateLabels(updateLabels);
/* if the update is modified */
if (pipeDream.interceptRefresh(update)) {
/* intercept and apply the update */
boolean toUpdateLabels = update.isUpdateLabels();
for (Iterator iter = update.getRefreshTargets().iterator(); iter
.hasNext();) {
super.refresh(iter.next(), toUpdateLabels);
}
} else {
super.refresh(element, updateLabels);
}
} else {
super.refresh(element, updateLabels);
}
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.viewers.Viewer#setSelection(org.eclipse.jface.viewers.ISelection, boolean)
*/
public void setSelection(ISelection selection, boolean reveal) {
if(selection instanceof IStructuredSelection) {
IStructuredSelection sSelection = (IStructuredSelection) selection;
INavigatorPipelineService pipeDream = contentService
.getPipelineService();
PipelinedViewerUpdate update = new PipelinedViewerUpdate();
update.getRefreshTargets().addAll(sSelection.toList());
update.setUpdateLabels(false);
/* if the update is modified */
if (pipeDream.interceptRefresh(update)) {
/* intercept and apply the update */
super.setSelection(new StructuredSelection(update.getRefreshTargets().toArray()) , reveal);
} else {
super.setSelection(selection, reveal);
}
}
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.AbstractTreeViewer#setSelectionToWidget(java.util.List, boolean)
*/
protected void setSelectionToWidget(List v, boolean reveal) {
clearSelectionCache();
super.setSelectionToWidget(v, reveal);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.AbstractTreeViewer#handleDoubleSelect(org.eclipse.swt.events.SelectionEvent)
*/
protected void handleDoubleSelect(SelectionEvent event) {
clearSelectionCache();
super.handleDoubleSelect(event);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#handleOpen(org.eclipse.swt.events.SelectionEvent)
*/
protected void handleOpen(SelectionEvent event) {
clearSelectionCache();
super.handleOpen(event);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#handlePostSelect(org.eclipse.swt.events.SelectionEvent)
*/
protected void handlePostSelect(SelectionEvent e) {
clearSelectionCache();
super.handlePostSelect(e);
}
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.StructuredViewer#handleSelect(org.eclipse.swt.events.SelectionEvent)
*/
protected void handleSelect(SelectionEvent event) {
clearSelectionCache();
super.handleSelect(event);
}
/**
* Clears the selection cache.
*/
private void clearSelectionCache() {
cachedSelection = null;
}
/**
* Returns the current selection.
* <p>
* Note that as of 3.2.1 and 3.3, the common viewer caches its selection.
* Clients must not set the selection of the viewer's tree control directly.
* </p>
*
* @see org.eclipse.jface.viewers.AbstractTreeViewer#getSelection()
*/
public ISelection getSelection() {
if (cachedSelection == null) {
cachedSelection = super.getSelection();
}
return cachedSelection;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#refresh(java.lang.Object)
*/
public void refresh(Object element) {
refresh(element, true);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.StructuredViewer#update(java.lang.Object,
* java.lang.String[])
*/
public void update(Object element, String[] properties) {
if(element != getInput()) {
NavigatorPipelineService pipeDream = (NavigatorPipelineService) contentService
.getPipelineService();
PipelinedViewerUpdate update = new PipelinedViewerUpdate();
update.getRefreshTargets().add(element);
update.setUpdateLabels(true);
/* if the update is modified */
if (pipeDream.interceptUpdate(update)) {
/* intercept and apply the update */
for (Iterator iter = update.getRefreshTargets().iterator(); iter
.hasNext();) {
super.refresh(iter.next(), true);
}
} else {
super.update(element, properties);
}
} else {
super.update(element, properties);
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
return contentService.toString() + " Viewer"; //$NON-NLS-1$
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.AbstractTreeViewer#internalRefresh(java.lang.Object,
* boolean)
*/
protected void internalRefresh(Object element, boolean updateLabels) {
if (element == null && getRoot() == null) {
return;
}
super.internalRefresh(element, updateLabels);
}
}