Package org.springframework.ide.eclipse.ui.navigator

Source Code of org.springframework.ide.eclipse.ui.navigator.SpringNavigator

/*******************************************************************************
* Copyright (c) 2008, 2009 Spring IDE Developers
* 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:
*     Spring IDE Developers - initial API and implementation
*******************************************************************************/
package org.springframework.ide.eclipse.ui.navigator;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IField;
import org.eclipse.jdt.core.IImportContainer;
import org.eclipse.jdt.core.IImportDeclaration;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaModelMarker;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.IMethod;
import org.eclipse.jdt.core.ISourceRange;
import org.eclipse.jdt.core.ISourceReference;
import org.eclipse.jdt.core.IType;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.SourceType;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
import org.eclipse.jdt.ui.IWorkingCopyManager;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewerExtension5;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.custom.StyledText;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPropertyListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.internal.navigator.NavigatorContentService;
import org.eclipse.ui.navigator.CommonNavigator;
import org.eclipse.ui.navigator.ILinkHelper;
import org.springframework.ide.eclipse.core.model.IModelElement;
import org.springframework.ide.eclipse.ui.SpringUIPlugin;
import org.springframework.ide.eclipse.ui.dialogs.WrappingStructuredSelection;
import org.springframework.ide.eclipse.ui.navigator.actions.ILinkHelperExtension;
import org.w3c.dom.Comment;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.Text;

/**
* {@link CommonNavigator} extension that supports a special "Link to Editor mode" that selects
* {@link IModelElement} instances based on selections in the XML files.
* <p>
* Actual resolution of {@link Element} instances to {@link IModelElement} instances is delegated to
* implementations of the {@link ILinkHelperExtension} interface. Those implementations can be
* contributed as usual by using the link helper content contribution of the common navigator
* framework.
* @author Christian Dupuis
* @since 2.2.0
*/
@SuppressWarnings("restriction")
public final class SpringNavigator extends CommonNavigator implements ISelectionListener {

  /** Mapping between working copy managers and open editors */
  private static Map<Object, Object> workingCopyManagersForEditors = new HashMap<Object, Object>();

  /**
   * Last selected element; stored in order to prevent updating on selecting the same element
   * again
   */
  private ISelection lastElement;

  private Object linkService;

  private IPropertyListener propertyListener;

  private Method linkServiceMethod;

  /**
   * Register the {@link ISelectionListener} with the workbench.
   */
  @Override
  public void createPartControl(Composite aParent) {
    super.createPartControl(aParent);
    getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener(this);
    propertyListener = new IPropertyListener() {

      public void propertyChanged(Object source, int propId) {
        if (propId == IS_LINKING_ENABLED_PROPERTY) {
          updateTreeViewer(SpringNavigator.this, lastElement, false);
        }
      }

    };
    addPropertyListener(propertyListener);

  }

  /**
   * Remove the {@link ISelectionListener} from the workbench.
   */
  @Override
  public void dispose() {
    getSite().getWorkbenchWindow().getSelectionService().removeSelectionListener(this);
    removePropertyListener(propertyListener);
    super.dispose();
  }

  /**
   * {@inheritDoc}
   */
  public void selectionChanged(IWorkbenchPart part, ISelection selection) {
    if (selection instanceof IStructuredSelection) {
      selection = new WrappingStructuredSelection((IStructuredSelection) selection);
    }
    updateTreeViewer(part, selection, true);
  }

  /**
   * Computes and returns the source reference. This is taken from the
   * computeHighlightRangeSourceReference() method in the JavaEditor class which is used to
   * populate the outline view
   * @return the computed source reference
   */
  private ISourceReference computeHighlightRangeSourceReference(JavaEditor editor) {
    ISourceViewer sourceViewer = editor.getViewer();
    if (sourceViewer == null)
      return null;

    StyledText styledText = sourceViewer.getTextWidget();
    if (styledText == null)
      return null;

    int caret = 0;
    if (sourceViewer instanceof ITextViewerExtension5) {
      ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer;
      caret = extension.widgetOffset2ModelOffset(styledText.getCaretOffset());
    }
    else {
      int offset = sourceViewer.getVisibleRegion().getOffset();
      caret = offset + styledText.getCaretOffset();
    }

    IJavaElement element = getElementAt(editor, caret, false);

    if (!(element instanceof ISourceReference))
      return null;

    if (element.getElementType() == IJavaElement.IMPORT_DECLARATION) {

      IImportDeclaration declaration = (IImportDeclaration) element;
      IImportContainer container = (IImportContainer) declaration.getParent();
      ISourceRange srcRange = null;
      try {
        srcRange = container.getSourceRange();
      }
      catch (JavaModelException e) {
      }

      if (srcRange != null && srcRange.getOffset() == caret)
        return container;
    }

    return (ISourceReference) element;
  }

  private void determineAndRefreshViewer(IWorkbenchPart part, ISelection selection,
      boolean ignoreSameSelection) {
    final Object element = getSelectedElement(part, selection);
    if (element == null || (element.equals(lastElement) && ignoreSameSelection)) {
      return;
    }
    if ((element instanceof IType || element instanceof IMethod || element instanceof IField
        || element instanceof Element || element instanceof IResource)
        && isLinkingEnabled()) {
      selectReveal(getCommonViewer(), element);
    }
    lastElement = selection;
  }

  /**
   * Returns the most narrow java element including the given offset. This is taken from the
   * getElementAt(int offset, boolean reconcile) method in the CompilationUnitEditor class.
   */
  private IJavaElement getElementAt(JavaEditor editor, int offset, boolean reconcile) {
    IWorkingCopyManager manager;
    if (workingCopyManagersForEditors.get(editor) instanceof IWorkingCopyManager) {
      manager = (IWorkingCopyManager) workingCopyManagersForEditors.get(editor);
    }
    else {
      manager = JavaPlugin.getDefault().getWorkingCopyManager();
    }
    ICompilationUnit unit = manager.getWorkingCopy(editor.getEditorInput());

    if (unit != null) {
      try {
        if (reconcile) {
          synchronized (unit) {
            unit.reconcile(ICompilationUnit.NO_AST, false, null, null);
          }
          IJavaElement elementAt = unit.getElementAt(offset);
          if (elementAt != null) {
            return elementAt;
          }
          // this is if the selection in the editor
          // is outside the {} of the class or aspect
          IJavaElement[] children = unit.getChildren();
          for (IJavaElement element : children) {
            if (element instanceof SourceType) {
              return element;
            }
          }
        }
        else if (unit.isConsistent()) {
          // Bug 96313 - if there is no IJavaElement for the
          // given offset, then check whether there are any
          // children for this CU. There are if you've selected
          // somewhere in the file and there aren't if there are
          // compilation errors. Therefore, return one of these
          // children and calculate the xrefs as though the user
          // wants to display the xrefs for the entire file
          IJavaElement elementAt = unit.getElementAt(offset);
          if (elementAt != null) {
            // a javaElement has been selected, therefore
            // no need to go any further
            return elementAt;
          }
          IResource res = unit.getCorrespondingResource();
          if (res instanceof IFile) {
            IFile file = (IFile) res;
            IProject containingProject = file.getProject();
            IMarker[] javaModelMarkers = containingProject.findMarkers(
                IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, false,
                IResource.DEPTH_INFINITE);
            for (IMarker marker : javaModelMarkers) {
              if (marker.getResource().equals(file)) {
                // there is an error in the file, therefore
                // we don't want to return any xrefs
                return null;
              }
            }
          }
          // the selection was outside an IJavaElement, however, there
          // are children for this compilation unit so we think you've
          // selected outside of a java element.
          if (elementAt == null && unit.getChildren().length != 0) {
            return unit.getChildren()[0];
          }
        }

      }
      catch (JavaModelException x) {
        if (!x.isDoesNotExist())
          JavaPlugin.log(x.getStatus());
        // nothing found, be tolerant and go on
      }
      catch (CoreException e) {
      }
    }

    return null;
  }

  private synchronized Object getInternalLinkHelperService() {
    if (linkService == null) {
      try {
        try {
          // e3.5: get helper from common navigator
          Method method = CommonNavigator.class.getDeclaredMethod("getLinkHelperService"); //$NON-NLS-1$
          method.setAccessible(true);
          linkService = method.invoke(this);
        }
        catch (NoSuchMethodException e) {
          // e3.3, e3.4: instantiate helper
          Class<?> clazz = Class
              .forName("org.eclipse.ui.internal.navigator.extensions.LinkHelperService"); //$NON-NLS-1$
          Constructor<?> constructor = clazz
              .getConstructor(NavigatorContentService.class);
          linkService = constructor
              .newInstance((NavigatorContentService) getCommonViewer()
                  .getNavigatorContentService());
        }
        linkServiceMethod = linkService.getClass().getDeclaredMethod("getLinkHelpersFor", Object.class); //$NON-NLS-1$
      }
      catch (Throwable e) {
        SpringUIPlugin.log(e);
      }
    }
    return linkService;
  }
 
  private ILinkHelper[] getInternalLinkHelpersFor(Object object) {
    if (getInternalLinkHelperService() != null && linkServiceMethod != null) {
      try {
        return (ILinkHelper[]) linkServiceMethod.invoke(getInternalLinkHelperService(), object);
      }
      catch (IllegalArgumentException e) {
      }
      catch (IllegalAccessException e) {
      }
      catch (InvocationTargetException e) {
      }
    }
    return new ILinkHelper[0];
  }

  /**
   * Retrieves the element as represented by the given <code>selection</code>.
   */
  private Object getSelectedElement(IWorkbenchPart part, ISelection selection) {
    Object selectedElement = getSelectedJavaElement(part, selection);

    if (selectedElement == null) {
      selectedElement = getSelectedXmlElement(selection);

    }
    return selectedElement;
  }

  private IJavaElement getSelectedJavaElement(IWorkbenchPart part, ISelection selection) {
    if (selection instanceof IStructuredSelection) {
      IStructuredSelection structuredSelection = (IStructuredSelection) selection;
      Object first = structuredSelection.getFirstElement();
      if (first instanceof IJavaElement) {
        if (!(first instanceof IJavaProject)) {
          return (IJavaElement) first;
        }
      }
    }
    else if (part instanceof IEditorPart && selection instanceof ITextSelection) {
      if (part instanceof JavaEditor) {
        JavaEditor je = (JavaEditor) part;
        ISourceReference sourceRef = computeHighlightRangeSourceReference(je);
        IJavaElement javaElement = (IJavaElement) sourceRef;
        return javaElement;
      }
    }
    return null;
  }

  private Object getSelectedXmlElement(ISelection selection) {
    Object selectedElement = null;
    if (selection instanceof IStructuredSelection) {
      IStructuredSelection structSelection = (IStructuredSelection) selection;
      Object obj = structSelection.getFirstElement();
      if (obj instanceof Element) {
        selectedElement = obj;
      }
      else if (obj instanceof Text) {
        Node parent = ((Text) obj).getParentNode();
        if (parent instanceof Element) {
          selectedElement = parent;
        }
      }
      else if (obj instanceof Comment) {
        Node parent = ((Comment) obj).getParentNode();
        if (parent instanceof Element) {
          selectedElement = parent;
        }
      }
    }
    return selectedElement;
  }

  private void selectReveal(TreeViewer viewer, Object element) {
    ILinkHelper[] helpers = getInternalLinkHelpersFor(element);
    for (ILinkHelper helper : helpers) {
      if (helper instanceof ILinkHelperExtension) {
        ISelection selection = ((ILinkHelperExtension) helper).findSelection(element);
        if (selection != null) {
          viewer.getTree().setRedraw(false);
          super.selectReveal(selection);
          viewer.getTree().setRedraw(true);
          break;
        }
      }
    }
  }

  private void updateTreeViewer(final IWorkbenchPart part, final ISelection selection,
      final boolean ignoreSameSelection) {
    // Abort if this happens after disposes
    Control ctrl = getCommonViewer().getControl();
    if (ctrl == null || ctrl.isDisposed()) {
      return;
    }

    // Are we in the UI thread?
    if (ctrl.getDisplay().getThread() == Thread.currentThread()) {
      determineAndRefreshViewer(part, selection, ignoreSameSelection);
    }
    else {
      ctrl.getDisplay().asyncExec(new Runnable() {
        public void run() {

          // Abort if this happens after disposes
          Control ctrl = getCommonViewer().getControl();
          if (ctrl == null || ctrl.isDisposed()) {
            return;
          }
          determineAndRefreshViewer(part, selection, ignoreSameSelection);
        }
      });
    }
  }

}
TOP

Related Classes of org.springframework.ide.eclipse.ui.navigator.SpringNavigator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.