AbstractTreeViewerAdvisor.java :  » IDE-Eclipse » team » org » eclipse » team » internal » ui » synchronize » Java Open Source

Java Open Source » IDE Eclipse » team 
team » org » eclipse » team » internal » ui » synchronize » AbstractTreeViewerAdvisor.java
/*******************************************************************************
 * Copyright (c) 2000, 2007 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.*;
import org.eclipse.core.resources.IResource;
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.core.synchronize.SyncInfo;
import org.eclipse.team.internal.ui.synchronize.actions.OpenInCompareAction;
import org.eclipse.team.ui.synchronize.*;
import org.eclipse.ui.*;

/**
 * Abstract superclass for tree viewer advisors
 */
public abstract class AbstractTreeViewerAdvisor extends StructuredViewerAdvisor implements IAdaptable {

  private ICompareNavigator nav;
  private INavigatable navigatable;
  
  /**
   * 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 class TreeCompareNavigator extends CompareNavigator {
    
    /* (non-Javadoc)
     * @see org.eclipse.compare.CompareNavigator#getNavigatables()
     */
    protected INavigatable[] getNavigatables() {
      INavigatable navigatable = getNavigatable();
      return new INavigatable[] { navigatable };
    }
    
    /* (non-Javadoc)
     * @see org.eclipse.compare.CompareNavigator#selectChange(boolean)
     */
    public boolean selectChange(boolean next) {
      if (getSubNavigator() != null) {
        if (getSubNavigator().hasChange(next)) {
          getSubNavigator().selectChange(next);
          return false;
        }
      }
      boolean noNextChange = super.selectChange(next);
      if (!noNextChange) {
        // Check to see if the selected element can be opened.
        // If it can't, try the next one
        Object selectedObject = AbstractTreeViewerAdvisor.this.getFirstElement((IStructuredSelection)getViewer().getSelection());
        if (!hasCompareInput(selectedObject)) {
          return selectChange(next);
        }
      }
      return noNextChange;
    }
    
    private boolean hasCompareInput(Object selectedObject) {
      SyncInfo syncInfo = getSyncInfo(selectedObject);
      if(syncInfo != null) {
        return syncInfo.getLocal().getType() == IResource.FILE;
      }
      ISynchronizeParticipant p = getConfiguration().getParticipant();
      if (p instanceof ModelSynchronizeParticipant) {
        ModelSynchronizeParticipant msp = (ModelSynchronizeParticipant) p;
        return msp.hasCompareInputFor(selectedObject);
      }
      return true;
    }

    private SyncInfo getSyncInfo(Object obj) {
      if (obj instanceof SyncInfoModelElement) {
        return ((SyncInfoModelElement) obj).getSyncInfo();
      } else {
        return null;
      }
    }

    /* (non-Javadoc)
     * @see org.eclipse.compare.CompareNavigator#hasChange(boolean)
     */
    public boolean hasChange(boolean next) {
      if (getSubNavigator() != null) {
        if (getSubNavigator().hasChange(next)) {
          return true;
        }
      }
      return super.hasChange(next);
    }

    private CompareNavigator getSubNavigator() {
      IWorkbenchSite ws = AbstractTreeViewerAdvisor.this.getConfiguration().getSite().getWorkbenchSite();
      if (ws instanceof IWorkbenchPartSite) {
        Object selectedObject = AbstractTreeViewerAdvisor.this.getFirstElement((IStructuredSelection)getViewer().getSelection());
        IEditorPart editor = OpenInCompareAction.findOpenCompareEditor((IWorkbenchPartSite)ws, selectedObject, getConfiguration().getParticipant());
        if(editor != null) {
          // if an existing editor is open on the current selection, use it       
          CompareEditorInput input = (CompareEditorInput)editor.getEditorInput();
          ICompareNavigator navigator = input.getNavigator();
          if (navigator instanceof TreeCompareNavigator) {
            // The input knows to use the global navigator.
            // Assume it set the input navigator property
            navigator = (ICompareNavigator)AbstractTreeViewerAdvisor.this.getConfiguration().getProperty(SynchronizePageConfiguration.P_INPUT_NAVIGATOR);
          }
          if (navigator instanceof CompareNavigator) {
            return (CompareNavigator) navigator;
            
          }
        }
      }
      return null;
    }
    
  }
  
  private static boolean hasNextPrev(TreeViewer viewer, TreeItem item, boolean next) {
    if (item == null || !(viewer instanceof ITreeViewerAccessor))
      return false;
    TreeItem children[] = null;
    if (next) {
      if (viewer.isExpandable(item.getData()))
        return true;
      while(item != null) {
        TreeItem parent = item.getParentItem();
        if (parent != null)
          children = parent.getItems();
        else
          children = item.getParent().getItems();
        if (children != null && children.length > 0) {
          if (children[children.length - 1] != item) {
            // The item is not the last so there must be a next
            return true;
          } else {
            // Set the parent as the item and go up one more level
            item = parent;
          }
        }
      }
    } else {
      while(item != null) {
        TreeItem parent = item.getParentItem();
        if (parent != null)
          children = parent.getItems();
        else
          children = item.getParent().getItems();
        if (children != null && children.length > 0) {
          if (children[0] != item) {
            // The item is not the first so there must be a previous
            return true;
          } else {
            // Set the parent as the item and go up one more level
            item = parent;
          }
        }
      }
    }
    return false;
  }
  
  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 = getNextItem(viewer, next);
    if (item != null)
      setSelection(viewer, item, fireOpen, expandOnly);
    return item == null;
  }
    
  private static TreeItem getNextItem(TreeViewer viewer, boolean next) {
    TreeItem item = getCurrentItem(viewer);
    if (item != null) {
      while (true) {
        item = findNextPrev(viewer, item, next);
        if (item == null)
          break;
        if (item.getItemCount() <= 0)
          break;
      }
    }
    return item;
  }

  private static TreeItem getCurrentItem(TreeViewer viewer) {
    Tree tree = viewer.getTree();
    if (tree == null)
      return null;
    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];
      }
    }
    return item;
  }
  
  private static boolean hasChange(TreeViewer viewer, boolean next) {
    TreeItem item = getCurrentItem(viewer);
    if (item != null) {
      return hasNextPrev(viewer, item, next);
    }
    return false;
  }

  public AbstractTreeViewerAdvisor(ISynchronizePageConfiguration configuration) {
    super(configuration);
    ICompareNavigator nav = (ICompareNavigator)configuration.getProperty(SynchronizePageConfiguration.P_NAVIGATOR);
    if (nav == null) {
      configuration.setProperty(SynchronizePageConfiguration.P_NAVIGATOR, getAdapter(ICompareNavigator.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);
  }
  
  protected boolean hasChange(boolean next) {
    return hasChange((TreeViewer)getViewer(), next);
  }

  /* (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 == ICompareNavigator.class) {
      if(nav == null) {
        nav = new TreeCompareNavigator();
      }
      return nav;
    }
    if(adapter == INavigatable.class) {
      return getNavigatable();
    }
    return null;
  }

  private synchronized INavigatable getNavigatable() {
    if(navigatable == null) {
      navigatable = new INavigatable() {
        public boolean selectChange(int flag) {
          if (flag == INavigatable.FIRST_CHANGE) {
            getViewer().setSelection(StructuredSelection.EMPTY);
            flag = INavigatable.NEXT_CHANGE;
          } else if (flag == INavigatable.LAST_CHANGE) {
            getViewer().setSelection(StructuredSelection.EMPTY);
            flag = INavigatable.PREVIOUS_CHANGE;
          }
          return navigate((TreeViewer)getViewer(), flag == INavigatable.NEXT_CHANGE, true, false);
        }
      
        public boolean openSelectedChange() {
          Viewer v = getViewer();
          if (v instanceof ITreeViewerAccessor && !v.getControl().isDisposed()) {
            ITreeViewerAccessor tva = (ITreeViewerAccessor) v;
            tva.openSelection();
            return true;
          }
          return false;
        }
        public boolean hasChange(int changeFlag) {
          return AbstractTreeViewerAdvisor.this.hasChange(changeFlag == INavigatable.NEXT_CHANGE);
        }
        public Object getInput() {
          return getViewer().getInput();
        }
      
      };
    }
    return navigatable;
  }

  /**
   * 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;
  }
  
  private Object getFirstElement(IStructuredSelection selection) {
    Object element = getFirstElementOrPath(selection);
    if (element instanceof TreePath) {
      TreePath path = (TreePath) element;
      element = path.getLastSegment();
    }
    return element;
  }

  protected void expandToNextDiff(Object elementOrPath) {
    AbstractTreeViewerAdvisor.navigate((TreeViewer)getViewer(), true /* next */, false /* no-open */, true /* only-expand */);
  }
}
java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.