| /******************************************************************************* |
| * Copyright (c) 2008, 2009 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.wst.xml.ui.internal.actions; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.ResourceBundle; |
| |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.text.Position; |
| import org.eclipse.jface.text.TextSelection; |
| import org.eclipse.jface.text.source.Annotation; |
| import org.eclipse.jface.text.source.IAnnotationModel; |
| import org.eclipse.jface.text.source.IAnnotationModelExtension; |
| import org.eclipse.jface.viewers.IPostSelectionProvider; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.ISelectionChangedListener; |
| import org.eclipse.jface.viewers.ISelectionProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.osgi.util.NLS; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.ui.texteditor.IDocumentProvider; |
| import org.eclipse.ui.texteditor.ITextEditor; |
| import org.eclipse.ui.texteditor.TextEditorAction; |
| import org.eclipse.wst.sse.core.internal.provisional.text.IStructuredDocumentRegion; |
| import org.eclipse.wst.sse.core.internal.provisional.text.ITextRegion; |
| import org.eclipse.wst.xml.core.internal.provisional.document.IDOMNode; |
| import org.eclipse.wst.xml.ui.internal.XMLUIMessages; |
| import org.w3c.dom.Attr; |
| import org.w3c.dom.Node; |
| |
| /** |
| * Moves the cursor to the end tag if it is in a start tag, and vice versa. |
| * Also updates the matching tag annotation in the active editor. |
| * |
| * @author nitin |
| * |
| */ |
| class GoToMatchingTagAction extends TextEditorAction { |
| |
| private class UpdateListener implements ISelectionChangedListener { |
| public void selectionChanged(SelectionChangedEvent event) { |
| updateFor(event.getSelection()); |
| } |
| } |
| |
| private static final String ANNOTATION_TYPE = "org.eclipse.wst.xml.ui.matching.tag"; //$NON-NLS-1$ |
| private ISelectionChangedListener fUpdateListener = null; |
| static final boolean DEBUG = false; |
| |
| /** |
| * @param bundle |
| * @param prefix |
| * @param editor |
| * @param style |
| */ |
| GoToMatchingTagAction(ResourceBundle bundle, String prefix, ITextEditor editor) { |
| super(bundle, prefix, editor); |
| fUpdateListener = new UpdateListener(); |
| } |
| |
| void removeAnnotation(boolean allMatching) { |
| ITextEditor textEditor = getTextEditor(); |
| if (textEditor == null) { |
| if (DEBUG) { |
| System.out.println("no editor"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| IDocumentProvider documentProvider = textEditor.getDocumentProvider(); |
| if (documentProvider == null) { |
| if (DEBUG) { |
| System.out.println("no document provider"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| IAnnotationModel annotationModel = documentProvider.getAnnotationModel(textEditor.getEditorInput()); |
| if (annotationModel == null) { |
| if (DEBUG) { |
| System.out.println("no annotation model"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| |
| Iterator annotationIterator = annotationModel.getAnnotationIterator(); |
| List oldAnnotations = new ArrayList(); |
| while (annotationIterator.hasNext()) { |
| Annotation annotation = (Annotation) annotationIterator.next(); |
| if (ANNOTATION_TYPE.equals(annotation.getType())) { |
| annotation.markDeleted(true); |
| /** |
| * Sometimes it is supported, sometime's it is not. Confusing. |
| */ |
| try { |
| annotationIterator.remove(); |
| } |
| catch (UnsupportedOperationException e) { |
| oldAnnotations.add(annotation); |
| } |
| if (DEBUG) { |
| System.out.println("removed " + annotation); //$NON-NLS-1$ |
| } |
| if (!allMatching) |
| break; |
| } |
| } |
| if (!oldAnnotations.isEmpty()) { |
| int size = oldAnnotations.size(); |
| for (int i = 0; i < size; i++) { |
| annotationModel.removeAnnotation((Annotation) oldAnnotations.get(i)); |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.jface.action.Action#runWithEvent(org.eclipse.swt.widgets.Event) |
| */ |
| public void runWithEvent(Event event) { |
| super.runWithEvent(event); |
| if (getTextEditor() == null) |
| return; |
| |
| ISelection selection = getTextEditor().getSelectionProvider().getSelection(); |
| if (!selection.isEmpty() && selection instanceof IStructuredSelection && selection instanceof ITextSelection) { |
| Object o = ((IStructuredSelection) selection).getFirstElement(); |
| if (o instanceof IDOMNode) { |
| int offset = ((ITextSelection) selection).getOffset(); |
| IStructuredDocumentRegion matchRegion = null; |
| if (((Node) o).getNodeType() == Node.ATTRIBUTE_NODE) { |
| o = ((Attr) o).getOwnerElement(); |
| } |
| |
| int targetOffset = -1; |
| if (o instanceof IDOMNode) { |
| IDOMNode node = (IDOMNode) o; |
| IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); |
| if (startStructuredDocumentRegion != null && startStructuredDocumentRegion.containsOffset(offset)) { |
| matchRegion = ((IDOMNode) o).getEndStructuredDocumentRegion(); |
| if (matchRegion != null) |
| targetOffset = matchRegion.getStartOffset() + 2; |
| } |
| else { |
| IStructuredDocumentRegion endStructuredDocumentRegion = node.getEndStructuredDocumentRegion(); |
| if (endStructuredDocumentRegion != null && endStructuredDocumentRegion.containsOffset(offset)) { |
| matchRegion = ((IDOMNode) o).getStartStructuredDocumentRegion(); |
| if (matchRegion != null) |
| targetOffset = matchRegion.getStartOffset() + 1; |
| } |
| } |
| } |
| |
| if (targetOffset >= 0) { |
| getTextEditor().getSelectionProvider().setSelection(new TextSelection(targetOffset, 0)); |
| } |
| } |
| } |
| } |
| |
| /* |
| * (non-Javadoc) |
| * |
| * @see org.eclipse.ui.texteditor.TextEditorAction#setEditor(org.eclipse.ui.texteditor.ITextEditor) |
| */ |
| public void setEditor(ITextEditor editor) { |
| ITextEditor textEditor = getTextEditor(); |
| if (textEditor != null) { |
| removeAnnotation(true); |
| |
| ISelectionProvider selectionProvider = textEditor.getSelectionProvider(); |
| if (selectionProvider instanceof IPostSelectionProvider) { |
| ((IPostSelectionProvider) selectionProvider).removePostSelectionChangedListener(fUpdateListener); |
| } |
| } |
| super.setEditor(editor); |
| if (editor != null) { |
| ISelectionProvider selectionProvider = editor.getSelectionProvider(); |
| if (selectionProvider instanceof IPostSelectionProvider) { |
| ((IPostSelectionProvider) selectionProvider).addPostSelectionChangedListener(fUpdateListener); |
| } |
| |
| updateFor(selectionProvider.getSelection()); |
| } |
| } |
| |
| public void update() { |
| setEnabled(true); |
| |
| } |
| |
| void updateFor(ISelection selection) { |
| ITextEditor textEditor = getTextEditor(); |
| if (textEditor == null) { |
| if (DEBUG) { |
| System.out.println("no editor"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| IDocumentProvider documentProvider = textEditor.getDocumentProvider(); |
| if (documentProvider == null) { |
| if (DEBUG) { |
| System.out.println("no document provider"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| IAnnotationModel annotationModel = documentProvider.getAnnotationModel(textEditor.getEditorInput()); |
| if (annotationModel == null || !(annotationModel instanceof IAnnotationModelExtension)) { |
| if (DEBUG) { |
| System.out.println("no annotation model"); //$NON-NLS-1$ |
| } |
| return; |
| } |
| |
| List oldAnnotations = new ArrayList(2); |
| Iterator annotationIterator = annotationModel.getAnnotationIterator(); |
| while (annotationIterator.hasNext()) { |
| Annotation annotation = (Annotation) annotationIterator.next(); |
| if (ANNOTATION_TYPE.equals(annotation.getType())) { |
| annotation.markDeleted(true); |
| if (DEBUG) { |
| System.out.println("removing " + annotation); //$NON-NLS-1$ |
| } |
| oldAnnotations.add(annotation); |
| } |
| } |
| |
| Map newAnnotations = new HashMap(); |
| if (!selection.isEmpty() && selection instanceof IStructuredSelection && selection instanceof ITextSelection) { |
| Object o = ((IStructuredSelection) selection).getFirstElement(); |
| if (o instanceof IDOMNode) { |
| int offset = ((ITextSelection) selection).getOffset(); |
| IStructuredDocumentRegion matchRegion = null; |
| if (((Node) o).getNodeType() == Node.ATTRIBUTE_NODE) { |
| o = ((Attr) o).getOwnerElement(); |
| } |
| |
| Position pStart = null; |
| Position pEnd = null; |
| String tag = ""; //$NON-NLS-1$ |
| if (o instanceof IDOMNode) { |
| IDOMNode node = (IDOMNode) o; |
| IStructuredDocumentRegion startStructuredDocumentRegion = node.getStartStructuredDocumentRegion(); |
| if (startStructuredDocumentRegion != null && startStructuredDocumentRegion.containsOffset(offset)) { |
| if (startStructuredDocumentRegion.getNumberOfRegions() > 1) { |
| ITextRegion nameRegion = startStructuredDocumentRegion.getRegions().get(1); |
| pStart = new Position(startStructuredDocumentRegion.getStartOffset(nameRegion), nameRegion.getTextLength()); |
| tag = startStructuredDocumentRegion.getText(nameRegion); |
| } |
| matchRegion = ((IDOMNode) o).getEndStructuredDocumentRegion(); |
| if (matchRegion != null && matchRegion.getNumberOfRegions() > 1) { |
| ITextRegion nameRegion = matchRegion.getRegions().get(1); |
| pEnd = new Position(matchRegion.getStartOffset(nameRegion), nameRegion.getTextLength()); |
| } |
| } |
| else { |
| IStructuredDocumentRegion endStructuredDocumentRegion = node.getEndStructuredDocumentRegion(); |
| if (endStructuredDocumentRegion != null && endStructuredDocumentRegion.containsOffset(offset)) { |
| if (endStructuredDocumentRegion.getNumberOfRegions() > 1) { |
| ITextRegion nameRegion = endStructuredDocumentRegion.getRegions().get(1); |
| pEnd = new Position(endStructuredDocumentRegion.getStartOffset(nameRegion), nameRegion.getTextLength()); |
| tag = endStructuredDocumentRegion.getText(nameRegion); |
| } |
| matchRegion = ((IDOMNode) o).getStartStructuredDocumentRegion(); |
| if (matchRegion != null && matchRegion.getNumberOfRegions() > 1) { |
| ITextRegion nameRegion = matchRegion.getRegions().get(1); |
| pStart = new Position(matchRegion.getStartOffset(nameRegion), nameRegion.getTextLength()); |
| } |
| } |
| } |
| } |
| if (pStart != null && pEnd != null) { |
| Annotation annotation = new Annotation(ANNOTATION_TYPE, false, NLS.bind(XMLUIMessages.gotoMatchingTag_start, tag)); |
| newAnnotations.put(annotation, pStart); |
| if (DEBUG) { |
| System.out.println("adding " + annotation); //$NON-NLS-1$ |
| } |
| annotation = new Annotation(ANNOTATION_TYPE, false, NLS.bind(XMLUIMessages.gotoMatchingTag_end, tag)); |
| newAnnotations.put(annotation, pEnd); |
| if (DEBUG) { |
| System.out.println("adding " + annotation); //$NON-NLS-1$ |
| } |
| } |
| } |
| } |
| ((IAnnotationModelExtension) annotationModel).replaceAnnotations((Annotation[]) oldAnnotations.toArray(new Annotation[oldAnnotations.size()]), newAnnotations); |
| } |
| } |