blob: dbcf58e0ba67ad8dc8fea3876d9779e652ce8123 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 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.team.internal.ui.synchronize;
import org.eclipse.compare.internal.INavigatable;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.viewers.*;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.team.ui.synchronize.ISynchronizePageConfiguration;
/**
* Abstract superclass for tree viewer advisors
*/
public class AbstractTreeViewerAdvisor extends StructuredViewerAdvisor implements IAdaptable {
private INavigatable nav;
/**
* Interface used to implement navigation for tree viewers. This interface is used by
* {@link TreeViewerAdvisor#navigate(TreeViewer, boolean, boolean, boolean) to open}
* selections and navigate.
*/
public interface ITreeViewerAccessor {
public void createChildren(TreeItem item);
public void openSelection();
}
private static TreeItem findNextPrev(TreeViewer viewer, TreeItem item, boolean next) {
if (item == null || !(viewer instanceof ITreeViewerAccessor))
return null;
TreeItem children[] = null;
ITreeViewerAccessor treeAccessor = (ITreeViewerAccessor) viewer;
if (!next) {
TreeItem parent = item.getParentItem();
if (parent != null)
children = parent.getItems();
else
children = item.getParent().getItems();
if (children != null && children.length > 0) {
// goto previous child
int index = 0;
for (; index < children.length; index++)
if (children[index] == item)
break;
if (index > 0) {
item = children[index - 1];
while (true) {
treeAccessor.createChildren(item);
int n = item.getItemCount();
if (n <= 0)
break;
item.setExpanded(true);
item = item.getItems()[n - 1];
}
// previous
return item;
}
}
// go up
return parent;
} else {
item.setExpanded(true);
treeAccessor.createChildren(item);
if (item.getItemCount() > 0) {
// has children: go down
children = item.getItems();
return children[0];
}
while (item != null) {
children = null;
TreeItem parent = item.getParentItem();
if (parent != null)
children = parent.getItems();
else
children = item.getParent().getItems();
if (children != null && children.length > 0) {
// goto next child
int index = 0;
for (; index < children.length; index++)
if (children[index] == item)
break;
if (index < children.length - 1) {
// next
return children[index + 1];
}
}
// go up
item = parent;
}
}
return item;
}
private static void setSelection(TreeViewer viewer, TreeItem ti, boolean fireOpen, boolean expandOnly) {
if (ti != null) {
Object data= ti.getData();
if (data != null) {
// Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
ISelection selection = new StructuredSelection(data);
if (expandOnly) {
viewer.expandToLevel(data, 0);
} else {
viewer.setSelection(selection, true);
ISelection currentSelection = viewer.getSelection();
if (fireOpen && currentSelection != null && selection.equals(currentSelection)) {
if (viewer instanceof ITreeViewerAccessor) {
((ITreeViewerAccessor) viewer).openSelection();
}
}
}
}
}
}
/**
* Selects the next (or previous) node of the current selection.
* If there is no current selection the first (last) node in the tree is selected.
* Wraps around at end or beginning.
* Clients may not override.
* @param viewer
*
* @param next if <code>true</code> the next node is selected, otherwise the previous node
* @param fireOpen
* @param expandOnly
* @return <code>true</code> if at end (or beginning)
*/
public static boolean navigate(TreeViewer viewer, boolean next, boolean fireOpen, boolean expandOnly) {
Tree tree = viewer.getTree();
if (tree == null)
return false;
TreeItem item = null;
TreeItem children[] = tree.getSelection();
if (children != null && children.length > 0)
item = children[0];
if (item == null) {
children = tree.getItems();
if (children != null && children.length > 0) {
item = children[0];
if (item != null && item.getItemCount() <= 0) {
setSelection(viewer, item, fireOpen, expandOnly); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
return false;
}
}
}
while (true) {
item = findNextPrev(viewer, item, next);
if (item == null)
break;
if (item.getItemCount() <= 0)
break;
}
if (item != null) {
setSelection(viewer, item, fireOpen, expandOnly); // Fix for http://dev.eclipse.org/bugs/show_bug.cgi?id=20106
return false;
}
return true;
}
public AbstractTreeViewerAdvisor(ISynchronizePageConfiguration configuration) {
super(configuration);
INavigatable nav = (INavigatable)configuration.getProperty(SynchronizePageConfiguration.P_NAVIGATOR);
if (nav == null) {
configuration.setProperty(SynchronizePageConfiguration.P_NAVIGATOR, getAdapter(INavigatable.class));
}
configuration.addActionContribution(new NavigationActionGroup());
}
/**
* Allow navigation in tree viewers.
*
* @param next if <code>true</code> then navigate forwards, otherwise navigate
* backwards.
* @return <code>true</code> if the end is reached, and <code>false</code> otherwise.
*/
public boolean navigate(boolean next) {
return navigate((TreeViewer)getViewer(), next, false, false);
}
/* (non-Javadoc)
* Allow adding an advisor to the PartNavigator and support coordinated
* navigation between several objects.
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
public Object getAdapter(Class adapter) {
if(adapter == INavigatable.class) {
if(nav == null) {
nav = new INavigatable() {
public boolean gotoDifference(boolean next) {
return AbstractTreeViewerAdvisor.this.navigate(next);
}
};
}
return nav;
}
return null;
}
/**
* Handles a double-click event from the viewer. Expands or collapses a folder when double-clicked.
*
* @param viewer the viewer
* @param event the double-click event
*/
protected boolean handleDoubleClick(StructuredViewer viewer, DoubleClickEvent event) {
if (super.handleDoubleClick(viewer, event)) return true;
IStructuredSelection selection = (IStructuredSelection) event.getSelection();
Object element = getFirstElementOrPath(selection);
AbstractTreeViewer treeViewer = (AbstractTreeViewer) getViewer();
if(element != null) {
if (treeViewer.getExpandedState(element)) {
treeViewer.collapseToLevel(element, AbstractTreeViewer.ALL_LEVELS);
} else {
expandToNextDiff(element);
}
}
return true;
}
private Object getFirstElementOrPath(IStructuredSelection selection) {
if (selection instanceof TreeSelection) {
TreeSelection ts = (TreeSelection) selection;
TreePath[] paths = ts.getPaths();
if (paths.length > 0)
return paths[0];
}
Object element = selection.getFirstElement();
return element;
}
protected void expandToNextDiff(Object elementOrPath) {
AbstractTreeViewerAdvisor.navigate((TreeViewer)getViewer(), true /* next */, false /* no-open */, true /* only-expand */);
}
}