| /******************************************************************************* |
| * Copyright (c) 2001, 2004 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 |
| * Jens Lukowski/Innoopract - initial renaming/restructuring |
| * |
| *******************************************************************************/ |
| package org.eclipse.wst.sse.ui.internal; |
| |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Vector; |
| |
| import org.eclipse.jface.text.ITextSelection; |
| import org.eclipse.jface.text.ITextViewer; |
| import org.eclipse.jface.viewers.DoubleClickEvent; |
| import org.eclipse.jface.viewers.IDoubleClickListener; |
| import org.eclipse.jface.viewers.ISelection; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.SelectionChangedEvent; |
| import org.eclipse.swt.custom.StyledText; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.wst.sse.core.IModelStateListener; |
| import org.eclipse.wst.sse.core.IStructuredModel; |
| import org.eclipse.wst.sse.core.IndexedRegion; |
| import org.eclipse.wst.sse.core.util.Debug; |
| import org.eclipse.wst.sse.core.util.Utilities; |
| import org.eclipse.wst.sse.ui.CaretMediator; |
| import org.eclipse.wst.sse.ui.ViewerSelectionManager; |
| import org.eclipse.wst.sse.ui.extensions.spellcheck.SpellCheckSelectionListener; |
| import org.eclipse.wst.sse.ui.extensions.spellcheck.SpellCheckSelectionManager; |
| import org.eclipse.wst.sse.ui.view.events.CaretEvent; |
| import org.eclipse.wst.sse.ui.view.events.INodeSelectionListener; |
| import org.eclipse.wst.sse.ui.view.events.ITextSelectionListener; |
| import org.eclipse.wst.sse.ui.view.events.NodeSelectionChangedEvent; |
| import org.eclipse.wst.sse.ui.view.events.TextSelectionChangedEvent; |
| |
| |
| public class ViewerSelectionManagerImpl implements ViewerSelectionManager, SpellCheckSelectionManager { |
| |
| class InternalModelStateListener implements IModelStateListener { |
| |
| public void modelAboutToBeChanged(IStructuredModel model) { |
| setModelChanging(true); |
| } |
| |
| public void modelChanged(IStructuredModel model) { |
| setModelChanging(false); |
| } |
| |
| public void modelDirtyStateChanged(IStructuredModel model, boolean isDirty) { |
| } |
| |
| public void modelResourceDeleted(IStructuredModel model) { |
| } |
| |
| public void modelResourceMoved(IStructuredModel originalmodel, IStructuredModel movedmodel) { |
| } |
| |
| } |
| |
| private CaretMediator fCaretMeditator; |
| private int fCaretPosition = 0; |
| protected IStructuredModel fModel; |
| private boolean fModelChanging = false; |
| |
| private IDoubleClickListener[] fNodeDoubleClickListeners; |
| private INodeSelectionListener[] fNodeSelectionListeners; |
| private List fSelectedNodes; |
| |
| // ISpellCheckSelectionManager |
| protected SpellCheckSelectionListener[] fSpellCheckSelectionListeners; |
| private int fTextSelectionEnd; |
| // TODO: private field never read locally |
| IndexedRegion fTextSelectionEndNode; |
| private ITextSelectionListener[] fTextSelectionListeners; |
| private int fTextSelectionStart; |
| // TODO: private field never read locally |
| IndexedRegion fTextSelectionStartNode; |
| private ITextViewer fTextViewer; |
| private InternalModelStateListener internalModelStateListener; |
| // TODO: private field never read locally |
| boolean isFiringNodeDoubleClick = false; |
| private boolean isFiringNodeSelectionChanged = false; |
| |
| public ViewerSelectionManagerImpl() { |
| internalModelStateListener = new InternalModelStateListener(); |
| } |
| |
| public ViewerSelectionManagerImpl(ITextViewer textViewer) { |
| setTextViewer(textViewer); |
| |
| internalModelStateListener = new InternalModelStateListener(); |
| } |
| |
| public synchronized void addNodeDoubleClickListener(IDoubleClickListener listener) { |
| // since its most certainly an error if someone is trying to add a |
| // null listner, |
| // we'll flag it explicitly and ignore |
| if (listener == null) { |
| Logger.log(Logger.WARNING, "Likely error in ViewerSelectionManagerImpl::addNodeDoubleClickListener should not be called with null listener"); //$NON-NLS-1$ |
| return; |
| } |
| // make sure listlistener not already in listening array |
| // (and if it is, print a warning to aid debugging, if needed) |
| if (Utilities.contains(fNodeDoubleClickListeners, listener)) { |
| if (Debug.displayWarnings) { |
| System.out.println("ViewerSelectionManager::addNodeDoubleClickListener. listener " + listener + " was added more than once. "); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| } else { |
| if (Debug.debugStructuredDocument) { |
| System.out.println("ViewerSelectionManager::addNodeDoubleClickListener. Adding an instance of " + listener.getClass() + " as a listener on ViewerSelectionManager."); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| int oldSize = 0; |
| if (fNodeDoubleClickListeners != null) { |
| // normally won't be null, but we need to be sure, for first |
| // time through |
| oldSize = fNodeDoubleClickListeners.length; |
| } |
| int newSize = oldSize + 1; |
| IDoubleClickListener[] newListeners = new IDoubleClickListener[newSize]; |
| if (fNodeDoubleClickListeners != null) { |
| System.arraycopy(fNodeDoubleClickListeners, 0, newListeners, 0, oldSize); |
| } |
| // add listener to last position |
| newListeners[newSize - 1] = listener; |
| // |
| // now switch new for old |
| fNodeDoubleClickListeners = newListeners; |
| |
| } |
| } |
| |
| public synchronized void addNodeSelectionListener(INodeSelectionListener listener) { |
| // since its most certainly an error if someone is trying to add a |
| // null listner, |
| // we'll flag it explicitly and ignore |
| if (listener == null) { |
| Logger.log(Logger.WARNING, "Likely error in ViewerSelectionManagerImpl::addNodeSelectionListener should not but called with null listener"); //$NON-NLS-1$ |
| return; |
| } |
| // make sure listener is not already in listening array |
| // (and if it is, print a warning to aid debugging, if needed) |
| if (Utilities.contains(fNodeSelectionListeners, listener)) { |
| if (Debug.displayWarnings) { |
| System.out.println("ViewerSelectionManager::addNodeSelectionListener. listener " + listener + " was added more than once. "); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| } else { |
| if (Debug.debugStructuredDocument) { |
| System.out.println("ViewerSelectionManager::addNodeSelectionListener. Adding an instance of " + listener.getClass() + " as a listener on ViewerSelectionManager."); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| int oldSize = 0; |
| if (fNodeSelectionListeners != null) { |
| // normally won't be null, but we need to be sure, for first |
| // time through |
| oldSize = fNodeSelectionListeners.length; |
| } |
| int newSize = oldSize + 1; |
| INodeSelectionListener[] newListeners = new INodeSelectionListener[newSize]; |
| if (fNodeSelectionListeners != null) { |
| System.arraycopy(fNodeSelectionListeners, 0, newListeners, 0, oldSize); |
| } |
| // add listener to last position |
| newListeners[newSize - 1] = listener; |
| // |
| // now switch new for old |
| fNodeSelectionListeners = newListeners; |
| |
| } |
| } |
| |
| /** |
| * @see SpellCheckSelectionManager#addSpellCheckSelectionListener(SpellCheckSelectionListener) |
| */ |
| public void addSpellCheckSelectionListener(SpellCheckSelectionListener listener) { |
| // since its most certainly an error if someone is trying to add a |
| // null listner, |
| // we'll flag it explicitly and ignore |
| if (listener == null) { |
| Logger.log(Logger.WARNING, "Likely error in ViewerSelectionManagerImpl::addSpellCheckSelectionListener should not but called with null listener"); //$NON-NLS-1$ |
| return; |
| } |
| // make sure listener is not already in listening array |
| // (and if it is, print a warning to aid debugging, if needed) |
| |
| if (Utilities.contains(fSpellCheckSelectionListeners, listener)) { |
| if (Debug.displayWarnings) { |
| System.out.println("ViewerSelectionManager::addSpellCheckSelectionListener. listener " + listener + " was added more than once. "); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| } else { |
| if (Debug.debugStructuredDocument) { |
| System.out.println("ViewerSelectionManager::addSpellCheckSelectionListener. Adding an instance of " + listener.getClass() + " as a listener on ViewerSelectionManager."); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| int oldSize = 0; |
| if (fSpellCheckSelectionListeners != null) { |
| // normally won't be null, but we need to be sure, for first |
| // time through |
| oldSize = fSpellCheckSelectionListeners.length; |
| } |
| int newSize = oldSize + 1; |
| SpellCheckSelectionListener[] newListeners = new SpellCheckSelectionListener[newSize]; |
| if (fSpellCheckSelectionListeners != null) { |
| System.arraycopy(fSpellCheckSelectionListeners, 0, newListeners, 0, oldSize); |
| } |
| // add listener to last position |
| newListeners[newSize - 1] = listener; |
| // |
| // now switch new for old |
| fSpellCheckSelectionListeners = newListeners; |
| } |
| } |
| |
| public synchronized void addTextSelectionListener(ITextSelectionListener listener) { |
| // since its most certainly an error if someone is trying to add a |
| // null listner, |
| // we'll flag it explicitly and ignore |
| if (listener == null) { |
| Logger.log(Logger.WARNING, "Likely error in ViewerSelectionManagerImpl::addTextSelectionListener should not but called with null listener"); //$NON-NLS-1$ |
| return; |
| } |
| // make sure listener is not already in listening array |
| // (and if it is, print a warning to aid debugging, if needed) |
| if (Utilities.contains(fTextSelectionListeners, listener)) { |
| if (Debug.displayWarnings) { |
| System.out.println("ViewerSelectionManager::addTextSelectionListener. listener " + listener + " was added more than once. "); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| } else { |
| if (Debug.debugStructuredDocument) { |
| System.out.println("ViewerSelectionManager::addTextSelectionListener. Adding an instance of " + listener.getClass() + " as a listener on ViewerSelectionManager."); //$NON-NLS-2$//$NON-NLS-1$ |
| } |
| int oldSize = 0; |
| if (fTextSelectionListeners != null) { |
| // normally won't be null, but we need to be sure, for first |
| // time through |
| oldSize = fTextSelectionListeners.length; |
| } |
| int newSize = oldSize + 1; |
| ITextSelectionListener[] newListeners = new ITextSelectionListener[newSize]; |
| if (fTextSelectionListeners != null) { |
| System.arraycopy(fTextSelectionListeners, 0, newListeners, 0, oldSize); |
| } |
| // add listener to last position |
| newListeners[newSize - 1] = listener; |
| // |
| // now switch new for old |
| fTextSelectionListeners = newListeners; |
| |
| } |
| } |
| |
| /** |
| * This method listens to text widget caret movements. This method is |
| * called when a caret (insertion point) move occurs that is NOT the |
| * result of the text changing. Specifcally, as a result of mouse clicks, |
| * PAGE_UP, RIGHT_ARROW, etc. |
| */ |
| public void caretMoved(final CaretEvent event) { |
| if (!isModelChanging()) { |
| List selectedNodes = getTextWidgetSelectedNodes(event.getPosition()); |
| int caretPosition = event.getPosition(); |
| processSelectionChanged(event.getSource(), selectedNodes, caretPosition, caretPosition); |
| } |
| } |
| |
| protected void currentNodeChanged(Object source, List newSelectedNodes, int caretPosition) { |
| // save current node; make sure to clone the selected nodes list, or |
| // else there may be a side effect when listeners modify the list |
| fSelectedNodes = new Vector(newSelectedNodes); |
| // save current caret position |
| fCaretPosition = caretPosition; |
| // generate and fire event |
| NodeSelectionChangedEvent nodeSelectionChangedEvent = new NodeSelectionChangedEvent(source, newSelectedNodes, caretPosition); |
| fireNodeSelectionChangedEvent(nodeSelectionChangedEvent); |
| } |
| |
| /** |
| * Notifies of a double click. |
| * |
| * @param event |
| * event object describing the double-click |
| */ |
| public void doubleClick(DoubleClickEvent event) { |
| if (!isModelChanging()) |
| fireNodeDoubleClickEvent(event); |
| } |
| |
| protected void fireNodeDoubleClickEvent(DoubleClickEvent event) { |
| if ((fNodeDoubleClickListeners != null) && (!isModelChanging())) { |
| // we must assign listeners to local variable to be thread safe, |
| // since the add and remove listner methods |
| // can change this object's actual instance of the listener array |
| // from another thread |
| // (and since object assignment is atomic, we don't need to |
| // synchronize |
| isFiringNodeDoubleClick = true; |
| try { |
| IDoubleClickListener[] holdListeners = fNodeDoubleClickListeners; |
| |
| for (int i = 0; i < holdListeners.length; i++) { |
| holdListeners[i].doubleClick(event); |
| } |
| } finally { |
| isFiringNodeDoubleClick = false; |
| } |
| } |
| } |
| |
| protected void fireNodeSelectionChangedEvent(NodeSelectionChangedEvent event) { |
| if ((fNodeSelectionListeners != null) && (!isModelChanging())) { |
| // we must assign listeners to local variable to be thread safe, |
| // since the add and remove listner methods |
| // can change this object's actual instance of the listener array |
| // from another thread |
| // (and since object assignment is atomic, we don't need to |
| // synchronize |
| isFiringNodeSelectionChanged = true; |
| try { |
| INodeSelectionListener[] holdListeners = fNodeSelectionListeners; |
| |
| for (int i = 0; i < holdListeners.length; i++) { |
| holdListeners[i].nodeSelectionChanged(event); |
| } |
| } finally { |
| isFiringNodeSelectionChanged = false; |
| } |
| } |
| } |
| |
| protected void fireSpellCheckSelectionChangedEvent() { |
| if ((fSpellCheckSelectionListeners != null) && (!isModelChanging())) { |
| // we must assign listeners to local variable to be thread safe, |
| // since the add and remove listner methods |
| // can change this object's actual instance of the listener array |
| // from another thread |
| // (and since object assignment is atomic, we don't need to |
| // synchronize |
| SpellCheckSelectionListener[] holdListeners = fSpellCheckSelectionListeners; |
| // |
| for (int i = 0; i < holdListeners.length; i++) { |
| holdListeners[i].selectionChanged(); |
| } |
| } |
| } |
| |
| protected void fireTextSelectionChangedEvent(TextSelectionChangedEvent event) { |
| if ((fTextSelectionListeners != null) && (!isModelChanging())) { |
| // we must assign listeners to local variable to be thread safe, |
| // since the add and remove listner methods |
| // can change this object's actual instance of the listener array |
| // from another thread |
| // (and since object assignment is atomic, we don't need to |
| // synchronize |
| ITextSelectionListener[] holdListeners = fTextSelectionListeners; |
| // |
| for (int i = 0; i < holdListeners.length; i++) { |
| holdListeners[i].textSelectionChanged(event); |
| } |
| } |
| } |
| |
| public int getCaretPosition() { |
| return fCaretPosition; |
| } |
| |
| public List getSelectedNodes() { |
| return fSelectedNodes; |
| } |
| |
| public ITextViewer getTextViewer() { |
| return fTextViewer; |
| } |
| |
| protected List getTextWidgetSelectedNodes(int offset) { |
| if (fModel == null) |
| return new ArrayList(0); |
| |
| IndexedRegion firstSelectedNode = fModel.getIndexedRegion(offset); |
| fTextSelectionStartNode = firstSelectedNode; |
| fTextSelectionEndNode = firstSelectedNode; |
| |
| // Never send a "null" in the selection |
| List selectedNodes = null; |
| if (firstSelectedNode != null) { |
| selectedNodes = new ArrayList(1); |
| selectedNodes.add(firstSelectedNode); |
| } else { |
| selectedNodes = new ArrayList(0); |
| } |
| return selectedNodes; |
| } |
| |
| protected boolean isCurrentNodeChanged(List newSelectedNodes) { |
| return !newSelectedNodes.equals(fSelectedNodes); |
| } |
| |
| protected boolean isModelChanging() { |
| return fModelChanging; |
| } |
| |
| protected boolean isTextSelectionChanged(int textSelectionStart, int textSelectionEnd) { |
| return ((fTextSelectionStart != textSelectionStart) || (fTextSelectionEnd != textSelectionEnd)); |
| } |
| |
| protected void processSelectionChanged(Object source, List selectedNodes, int selectionStart, int selectionEnd) { |
| if (source == null) { |
| // source should not be null. |
| // log this and ignore this selection changed event. |
| // DMW: I "shortened" this log message by removing stack trace, |
| // after receiving log |
| // from support showing this error. It made the log file |
| // confusing. |
| // Not clear why the source was null, but probably only related to |
| // initialization, or 'startup' with file open. |
| Logger.log(Logger.ERROR, "ViewerSelectionManager::processSelectionChanged. Unexpected null source"); //$NON-NLS-1$ |
| } else { |
| if (isTextSelectionChanged(selectionStart, selectionEnd)) |
| textSelectionChanged(source, selectionStart, selectionEnd); |
| |
| if (isCurrentNodeChanged(selectedNodes)) |
| currentNodeChanged(source, selectedNodes, selectionEnd); |
| } |
| } |
| |
| public void release() { |
| setTextViewer(null); |
| |
| // remove this viewer selection manager from the old model's list of |
| // model state listeners |
| if (fModel != null) |
| fModel.removeModelStateListener(internalModelStateListener); |
| |
| // make sure the CaretMediator we created is released as well |
| fCaretMeditator.release(); |
| } |
| |
| public synchronized void removeNodeDoubleClickListener(IDoubleClickListener listener) { |
| if ((fNodeDoubleClickListeners != null) && (listener != null)) { |
| // if its not in the listeners, we'll ignore the request |
| if (Utilities.contains(fNodeDoubleClickListeners, listener)) { |
| int oldSize = fNodeDoubleClickListeners.length; |
| int newSize = oldSize - 1; |
| IDoubleClickListener[] newListeners = new IDoubleClickListener[newSize]; |
| int index = 0; |
| for (int i = 0; i < oldSize; i++) { |
| if (fNodeDoubleClickListeners[i] == listener) { // ignore |
| } else { |
| // copy old to new if its not the one we are removing |
| newListeners[index++] = fNodeDoubleClickListeners[i]; |
| } |
| } |
| // now that we have a new array, let's switch it for the old |
| // one |
| fNodeDoubleClickListeners = newListeners; |
| } |
| } |
| } |
| |
| public synchronized void removeNodeSelectionListener(INodeSelectionListener listener) { |
| if ((fNodeSelectionListeners != null) && (listener != null)) { |
| // if its not in the listeners, we'll ignore the request |
| if (Utilities.contains(fNodeSelectionListeners, listener)) { |
| int oldSize = fNodeSelectionListeners.length; |
| int newSize = oldSize - 1; |
| INodeSelectionListener[] newListeners = new INodeSelectionListener[newSize]; |
| int index = 0; |
| for (int i = 0; i < oldSize; i++) { |
| if (fNodeSelectionListeners[i] == listener) { // ignore |
| } else { |
| // copy old to new if its not the one we are removing |
| newListeners[index++] = fNodeSelectionListeners[i]; |
| } |
| } |
| // now that we have a new array, let's switch it for the old |
| // one |
| fNodeSelectionListeners = newListeners; |
| } |
| } |
| } |
| |
| /** |
| * @see SpellCheckSelectionManager#removeSpellCheckSelectionListener(SpellCheckSelectionListener) |
| */ |
| public void removeSpellCheckSelectionListener(SpellCheckSelectionListener listener) { |
| if ((fSpellCheckSelectionListeners != null) && (listener != null)) { |
| // if its not in the listeners, we'll ignore the request |
| if (Utilities.contains(fSpellCheckSelectionListeners, listener)) { |
| int oldSize = fSpellCheckSelectionListeners.length; |
| int newSize = oldSize - 1; |
| SpellCheckSelectionListener[] newListeners = new SpellCheckSelectionListener[newSize]; |
| int index = 0; |
| for (int i = 0; i < oldSize; i++) { |
| if (fSpellCheckSelectionListeners[i] == listener) { // ignore |
| } else { |
| // copy old to new if its not the one we are removing |
| newListeners[index++] = fSpellCheckSelectionListeners[i]; |
| } |
| } |
| // now that we have a new array, let's switch it for the old |
| // one |
| fSpellCheckSelectionListeners = newListeners; |
| } |
| } |
| } |
| |
| public synchronized void removeTextSelectionListener(ITextSelectionListener listener) { |
| if ((fTextSelectionListeners != null) && (listener != null)) { |
| // if its not in the listeners, we'll ignore the request |
| if (Utilities.contains(fTextSelectionListeners, listener)) { |
| int oldSize = fTextSelectionListeners.length; |
| int newSize = oldSize - 1; |
| ITextSelectionListener[] newListeners = new ITextSelectionListener[newSize]; |
| int index = 0; |
| for (int i = 0; i < oldSize; i++) { |
| if (fTextSelectionListeners[i] == listener) { // ignore |
| } else { |
| // copy old to new if its not the one we are removing |
| newListeners[index++] = fTextSelectionListeners[i]; |
| } |
| } |
| // now that we have a new array, let's switch it for the old |
| // one |
| fTextSelectionListeners = newListeners; |
| } |
| } |
| } |
| |
| public void selectionChanged(SelectionChangedEvent event) { |
| // If selection is fired as a result of processing a node change |
| // event, then ignore the selection. |
| if (isFiringNodeSelectionChanged || isModelChanging()) |
| return; |
| |
| ISelection eventSelection = event.getSelection(); |
| // handle Structured selections |
| if (eventSelection instanceof IStructuredSelection) { |
| IStructuredSelection selection = (IStructuredSelection) eventSelection; |
| // System.out.println("selection: " + event.getSource() + " [" + |
| // selection.toArray().length + "] " + |
| // selection.getFirstElement()); |
| List selectedNodes = selection.toList(); |
| int selectionStart = 0; |
| int selectionEnd = 0; |
| |
| // something selected |
| if (selectedNodes.size() > 0) { |
| IndexedRegion firstSelectedNode = (IndexedRegion) selectedNodes.get(0); |
| selectionStart = firstSelectedNode.getStartOffset(); |
| selectionEnd = firstSelectedNode.getEndOffset(); |
| |
| // remove all except the first selected node |
| selectedNodes = new Vector(1); |
| selectedNodes.add(firstSelectedNode); |
| } |
| |
| processSelectionChanged(event.getSource(), selectedNodes, selectionStart, selectionEnd); |
| } |
| // handle text selection changes |
| else if (eventSelection instanceof ITextSelection) { |
| ITextSelection selection = (ITextSelection) eventSelection; |
| // System.out.println("selection: " + event.getSource() + " (" + |
| // selection.getOffset() + "+=" + selection.getLength() + ")"); |
| int selectionStart = selection.getOffset(); |
| setCaretPosition(selectionStart); |
| int selectionEnd = selection.getOffset() + selection.getLength(); |
| if (true) { |
| // option 1: works great for Source Page editors and the XML |
| // and XSL Editors |
| List selectedNodes = getTextWidgetSelectedNodes(selection.getOffset()); |
| processSelectionChanged(event.getSource(), selectedNodes, selectionStart, selectionEnd); |
| } else { |
| // option 2: works with all of the above plus Page Designer, |
| // but not as clean nor perfectly |
| // TODO: switch to option 1 |
| Event selectionEvent = new Event(); |
| selectionEvent.widget = fTextViewer.getTextWidget(); |
| selectionEvent.display = fTextViewer.getTextWidget().getDisplay(); |
| selectionEvent.x = selectionStart; |
| selectionEvent.y = selectionEnd; |
| fTextViewer.getTextWidget().setSelection(selectionStart, selectionEnd); |
| widgetDefaultSelected(new SelectionEvent(selectionEvent)); |
| } |
| } |
| } |
| |
| protected void setCaretPosition(int caretPosition) { |
| fCaretPosition = caretPosition; |
| } |
| |
| public void setModel(IStructuredModel newModel) { |
| if (newModel != fModel) { |
| // remove this viewer selection manager from the old model's list |
| // of model state listeners |
| if (fModel != null) |
| fModel.removeModelStateListener(internalModelStateListener); |
| |
| fModel = newModel; |
| |
| // add this viewer selection manager to the new model's list of |
| // model state listeners |
| fModel.addModelStateListener(internalModelStateListener); |
| } |
| } |
| |
| protected void setModelChanging(boolean modelChanging) { |
| fModelChanging = modelChanging; |
| } |
| |
| /** |
| * This is the viewer who's caret postion we monitor to determine when to |
| * check if the node has changed. We don't actually need, or save, the |
| * viewer, but do need its text widget, and will register this viewer |
| * selection manager as a listener of the text widget's text selection. |
| */ |
| public void setTextViewer(ITextViewer newTextViewer) { |
| // unhook from previous, if any |
| if (fCaretMeditator != null) { |
| fCaretMeditator.removeCaretListener(this); |
| fCaretMeditator.setTextWidget(null); |
| } |
| if (fTextViewer != null) { |
| // fTextViewer.getSelectionProvider().removeSelectionChangedListener(this); |
| StyledText textWidget = fTextViewer.getTextWidget(); |
| if (textWidget != null) { |
| // listen to text selections |
| textWidget.removeSelectionListener(this); |
| } |
| } |
| |
| fTextViewer = newTextViewer; |
| |
| if (fTextViewer != null) { |
| // fTextViewer.getSelectionProvider().addSelectionChangedListener(this); |
| StyledText textWidget = fTextViewer.getTextWidget(); |
| if (textWidget != null) { |
| // create new caret mediator, if it doesn't exist yet |
| if (fCaretMeditator == null) { |
| fCaretMeditator = new CaretMediator(textWidget); |
| } else { |
| fCaretMeditator.setTextWidget(textWidget); |
| } |
| // and register as a listener |
| fCaretMeditator.addCaretListener(this); |
| |
| // listen to text selections |
| textWidget.addSelectionListener(this); |
| } |
| } |
| } |
| |
| protected void textSelectionChanged(Object source, int textSelectionStart, int textSelectionEnd) { |
| // save current text selection |
| fTextSelectionStart = textSelectionStart; |
| fTextSelectionEnd = textSelectionEnd; |
| // save current caret position |
| fCaretPosition = fTextSelectionEnd; |
| // generate and fire event |
| TextSelectionChangedEvent textSelectionChangedEvent = new TextSelectionChangedEvent(source, fTextSelectionStart, fTextSelectionEnd); |
| fireTextSelectionChangedEvent(textSelectionChangedEvent); |
| |
| // SpellCheck dialog also needs to listen text selection change |
| fireSpellCheckSelectionChangedEvent(); |
| } |
| |
| /** |
| * This method listens to text widget default selection changes. This |
| * method is called when default selection occurs in the control. For |
| * example, on some platforms default selection occurs in a List when the |
| * user double-clicks an item or types return in a Text. |
| */ |
| public void widgetDefaultSelected(SelectionEvent event) { |
| if (!isModelChanging()) { |
| List selectedNodes = getTextWidgetSelectedNodes(event.x); |
| int selectionStart = event.x; |
| int selectionEnd = event.y; |
| processSelectionChanged(event.getSource(), selectedNodes, selectionStart, selectionEnd); |
| } |
| } |
| |
| /** |
| * This method listens to text widget text selection changes. This method |
| * is called when the text selection in a text widget has changed. |
| */ |
| public void widgetSelected(SelectionEvent event) { |
| // If selection is fired as a result of processing a node change |
| // event, then ignore the selection. |
| if (isFiringNodeSelectionChanged || isModelChanging()) |
| return; |
| |
| widgetDefaultSelected(event); |
| } |
| } |