| /******************************************************************************* |
| * 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.ui.part; |
| |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import org.eclipse.jface.action.Action; |
| import org.eclipse.jface.action.IMenuManager; |
| import org.eclipse.jface.action.IToolBarManager; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.jface.viewers.StructuredSelection; |
| import org.eclipse.jface.viewers.TreeViewer; |
| import org.eclipse.ui.ISharedImages; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.internal.IWorkbenchGraphicConstants; |
| import org.eclipse.ui.internal.WorkbenchImages; |
| import org.eclipse.ui.internal.WorkbenchMessages; |
| |
| /** |
| * Implements a simple web style navigation metaphor for a <code>TreeViewer</code>. |
| * Home, back, and "drill into" functions are supported for the viewer, |
| * <p> |
| * To use the <code>DrillDownAdapter</code> .. |
| * </p> |
| * <ul> |
| * <li>Create an instance of <code>TreeViewer</code>. </li> |
| * <li>Create a <code>DrillDownAdapter</code> for the viewer. </li> |
| * <li>Create a container for your viewer with a toolbar or a popup menu. |
| * Add actions for "goBack", "goHome", and "goInto" to either one by calling |
| * </code>addNavigationActions</code> with the popup menu or toolbar.</li> |
| * </ol> |
| * <p> |
| * If the input for the underlying viewer is changed by something other than the |
| * adapter the <code>reset</code> method should be called. This will clear |
| * the drill stack and update the navigation buttons to reflect the new |
| * state of the underlying viewer. |
| * </p> |
| * </p> |
| */ |
| public class DrillDownAdapter implements ISelectionChangedListener { |
| private TreeViewer fChildTree; |
| |
| private DrillStack fDrillStack; |
| |
| private Action homeAction; |
| |
| private Action backAction; |
| |
| private Action forwardAction; |
| |
| /** |
| * Allocates a new DrillDownTreePart. |
| * |
| * @param tree the target tree for refocusing |
| */ |
| public DrillDownAdapter(TreeViewer tree) { |
| fDrillStack = new DrillStack(); |
| fChildTree = tree; |
| } |
| |
| /** |
| * Adds actions for "go back", "go home", and "go into" to a menu manager. |
| * |
| * @param manager is the target manager to update |
| */ |
| public void addNavigationActions(IMenuManager manager) { |
| createActions(); |
| manager.add(homeAction); |
| manager.add(backAction); |
| manager.add(forwardAction); |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Adds actions for "go back", "go home", and "go into" to a tool bar manager. |
| * |
| * @param toolBar is the target manager to update |
| */ |
| public void addNavigationActions(IToolBarManager toolBar) { |
| createActions(); |
| toolBar.add(homeAction); |
| toolBar.add(backAction); |
| toolBar.add(forwardAction); |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Returns whether expansion is possible for the current selection. This |
| * will only be true if it has children. |
| * |
| * @param element the object to test for expansion |
| * @return <code>true</code> if expansion is possible; otherwise |
| * return <code>false</code |
| */ |
| public boolean canExpand(Object element) { |
| return fChildTree.isExpandable(element); |
| } |
| |
| /** |
| * Returns whether "go back" is possible for child tree. This is only possible |
| * if the client has performed one or more drilling operations. |
| * |
| * @return <code>true</code> if "go back" is possible; <code>false</code> otherwise |
| */ |
| public boolean canGoBack() { |
| return fDrillStack.canGoBack(); |
| } |
| |
| /** |
| * Returns whether "go home" is possible for child tree. This is only possible |
| * if the client has performed one or more drilling operations. |
| * |
| * @return <code>true</code> if "go home" is possible; <code>false</code> otherwise |
| */ |
| public boolean canGoHome() { |
| return fDrillStack.canGoHome(); |
| } |
| |
| /** |
| * Returns whether "go into" is possible for child tree. This is only possible |
| * if the current selection in the client has one item and it has children. |
| * |
| * @return <code>true</code> if "go into" is possible; <code>false</code> otherwise |
| */ |
| public boolean canGoInto() { |
| IStructuredSelection oSelection = (IStructuredSelection) fChildTree |
| .getSelection(); |
| if (oSelection == null || oSelection.size() != 1) { |
| return false; |
| } |
| Object anElement = oSelection.getFirstElement(); |
| return canExpand(anElement); |
| } |
| |
| /** |
| * Create the actions for navigation. |
| * |
| * @param tree the target tree for refocusing |
| */ |
| private void createActions() { |
| // Only do this once. |
| if (homeAction != null) { |
| return; |
| } |
| |
| // Home. |
| homeAction = new Action(WorkbenchMessages.GoHome_text) { |
| public void run() { |
| goHome(); |
| } |
| }; |
| homeAction |
| .setToolTipText(WorkbenchMessages.GoHome_toolTip); |
| homeAction |
| .setImageDescriptor(WorkbenchImages |
| .getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_HOME_NAV)); |
| |
| // Back. |
| ISharedImages images = PlatformUI.getWorkbench().getSharedImages(); |
| backAction = new Action(WorkbenchMessages.GoBack_text) { |
| public void run() { |
| goBack(); |
| } |
| }; |
| backAction |
| .setToolTipText(WorkbenchMessages.GoBack_toolTip); |
| backAction.setImageDescriptor(images |
| .getImageDescriptor(ISharedImages.IMG_TOOL_BACK)); |
| backAction.setDisabledImageDescriptor(images |
| .getImageDescriptor(ISharedImages.IMG_TOOL_BACK_DISABLED)); |
| |
| // Forward. |
| forwardAction = new Action(WorkbenchMessages.GoInto_text) { |
| public void run() { |
| goInto(); |
| } |
| }; |
| forwardAction.setToolTipText(WorkbenchMessages.GoInto_toolTip); |
| forwardAction.setImageDescriptor(images |
| .getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD)); |
| forwardAction.setDisabledImageDescriptor(images |
| .getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD_DISABLED)); |
| |
| // Update the buttons when a selection change occurs. |
| fChildTree.addSelectionChangedListener(this); |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Expands the given items in the tree. The list of items passed should be |
| * derived by calling <code>getExpanded</code>. |
| * |
| * @param items is a list of items within the tree which should be expanded |
| */ |
| private void expand(List items) { |
| fChildTree.setExpandedElements(items.toArray()); |
| } |
| |
| /** |
| * Returns a list of elements corresponding to expanded nodes in |
| * child tree. |
| * |
| * @return a list of expandd elements |
| */ |
| private List getExpanded() { |
| return Arrays.asList(fChildTree.getExpandedElements()); |
| } |
| |
| /** |
| * Reverts the input for the tree back to the state when <code>goInto</code> |
| * was last called. |
| * <p> |
| * A frame is removed from the drill stack. Then that frame is used to reset the |
| * input and expansion state for the child tree. |
| * </p> |
| */ |
| public void goBack() { |
| Object currentInput = fChildTree.getInput(); |
| DrillFrame oFrame = fDrillStack.goBack(); |
| Object input = oFrame.getElement(); |
| fChildTree.setInput(input); |
| expand(oFrame.getExpansion()); |
| // if there was a selection, it should have been preserved, |
| // but if not, select the element that was drilled into |
| if (fChildTree.getSelection().isEmpty()) { |
| fChildTree |
| .setSelection(new StructuredSelection(currentInput), true); |
| } |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Reverts the input for the tree back to the state when the adapter was |
| * created. |
| * <p> |
| * All of the frames are removed from the drill stack. Then the oldest frame is |
| * used to reset the input and expansion state for the child tree. |
| * </p> |
| */ |
| public void goHome() { |
| Object currentInput = fChildTree.getInput(); |
| DrillFrame oFrame = fDrillStack.goHome(); |
| Object input = oFrame.getElement(); |
| fChildTree.setInput(input); |
| expand(oFrame.getExpansion()); |
| // if there was a selection, it should have been preserved, |
| // but if not, select the element that was last drilled into |
| if (fChildTree.getSelection().isEmpty()) { |
| fChildTree |
| .setSelection(new StructuredSelection(currentInput), true); |
| } |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Sets the input for the tree to the current selection. |
| * <p> |
| * The current input and expansion state are saved in a frame and added to the |
| * drill stack. Then the input for the tree is changed to be the current selection. |
| * The expansion state for the tree is maintained during the operation. |
| * </p><p> |
| * On return the client may revert back to the previous state by invoking |
| * <code>goBack</code> or <code>goHome</code>. |
| * </p> |
| */ |
| public void goInto() { |
| IStructuredSelection sel = (IStructuredSelection) fChildTree |
| .getSelection(); |
| Object element = sel.getFirstElement(); |
| goInto(element); |
| } |
| |
| /** |
| * Sets the input for the tree to a particular item in the tree. |
| * <p> |
| * The current input and expansion state are saved in a frame and added to the |
| * drill stack. Then the input for the tree is changed to be <code>newInput</code>. |
| * The expansion state for the tree is maintained during the operation. |
| * </p><p> |
| * On return the client may revert back to the previous state by invoking |
| * <code>goBack</code> or <code>goHome</code>. |
| * </p> |
| * |
| * @param newInput the new input element |
| */ |
| public void goInto(Object newInput) { |
| // If we can drill .. |
| if (canExpand(newInput)) { |
| // Save the old state. |
| Object oldInput = fChildTree.getInput(); |
| List expandedList = getExpanded(); |
| fDrillStack.add(new DrillFrame(oldInput, "null", expandedList));//$NON-NLS-1$ |
| |
| // Install the new state. |
| fChildTree.setInput(newInput); |
| expand(expandedList); |
| updateNavigationButtons(); |
| } |
| } |
| |
| /** |
| * Resets the drill down adapter. |
| * <p> |
| * This method is typically called when the input for the underlying view |
| * is reset by something other than the adapter. |
| * On return the drill stack has been cleared and the navigation buttons |
| * reflect the new state of the underlying viewer. |
| * </p> |
| */ |
| public void reset() { |
| fDrillStack.reset(); |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Updates the navigation buttons when a selection change occurs |
| * in the tree. |
| */ |
| public void selectionChanged(SelectionChangedEvent event) { |
| updateNavigationButtons(); |
| } |
| |
| /** |
| * Updates the enabled state for each navigation button. |
| */ |
| protected void updateNavigationButtons() { |
| if (homeAction != null) { |
| homeAction.setEnabled(canGoHome()); |
| backAction.setEnabled(canGoBack()); |
| forwardAction.setEnabled(canGoInto()); |
| } |
| } |
| } |