/******************************************************************************* * Copyright (c) 2008, 2017 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.compare.internal; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.widgets.Widget; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.ListenerList; 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.SelectionChangedEvent; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.text.TextSelection; import org.eclipse.jface.text.TextViewer; /** * A selection provider for view parts with more that one viewer. Tracks the * focus of the viewers to provide the correct selection. * * This is a modified version of * org.eclipse.jdt.internal.ui.viewsupport.SelectionProviderMediator */ public class CompareEditorSelectionProvider implements IPostSelectionProvider { private class InternalListener implements ISelectionChangedListener, FocusListener { @Override public void selectionChanged(SelectionChangedEvent event) { doSelectionChanged(event); } @Override public void focusGained(FocusEvent e) { // expecting a StyledText widget here doFocusChanged(e.widget); } @Override public void focusLost(FocusEvent e) { // do not reset due to focus behavior on GTK //fViewerInFocus= null; } } private class InternalPostSelectionListener implements ISelectionChangedListener { @Override public void selectionChanged(SelectionChangedEvent event) { doPostSelectionChanged(event); } } private TextViewer[] fViewers; private TextViewer fViewerInFocus; private ListenerList fSelectionChangedListeners; private ListenerList fPostSelectionChangedListeners; public CompareEditorSelectionProvider() { fSelectionChangedListeners = new ListenerList<>(); fPostSelectionChangedListeners = new ListenerList<>(); // nothing more to do here, Compare Editor is initializing } /** * @param viewers All viewers that can provide a selection * @param viewerInFocus the viewer currently in focus or null */ public void setViewers(TextViewer[] viewers, TextViewer viewerInFocus) { Assert.isNotNull(viewers); fViewers= viewers; InternalListener listener= new InternalListener(); fViewerInFocus= viewerInFocus; for (int i= 0; i < fViewers.length; i++) { TextViewer viewer= fViewers[i]; viewer.addSelectionChangedListener(listener); viewer.addPostSelectionChangedListener(new InternalPostSelectionListener()); StyledText textWidget = viewer.getTextWidget(); textWidget.addFocusListener(listener); } } private void doFocusChanged(Widget control) { for (int i= 0; i < fViewers.length; i++) { if (fViewers[i].getTextWidget() == control) { propagateFocusChanged(fViewers[i]); return; } } } final void doPostSelectionChanged(SelectionChangedEvent event) { ISelectionProvider provider= event.getSelectionProvider(); if (provider == fViewerInFocus) { firePostSelectionChanged(); } } final void doSelectionChanged(SelectionChangedEvent event) { ISelectionProvider provider= event.getSelectionProvider(); if (provider == fViewerInFocus) { fireSelectionChanged(); } } final void propagateFocusChanged(TextViewer viewer) { if (viewer != fViewerInFocus) { // OK to compare by identity fViewerInFocus= viewer; fireSelectionChanged(); firePostSelectionChanged(); } } private void fireSelectionChanged() { if (fSelectionChangedListeners != null) { SelectionChangedEvent event= new SelectionChangedEvent(this, getSelection()); for (ISelectionChangedListener listener : fSelectionChangedListeners) { listener.selectionChanged(event); } } } private void firePostSelectionChanged() { if (fPostSelectionChangedListeners != null) { SelectionChangedEvent event= new SelectionChangedEvent(this, getSelection()); for (ISelectionChangedListener listener: fPostSelectionChangedListeners) { listener.selectionChanged(event); } } } @Override public void addSelectionChangedListener(ISelectionChangedListener listener) { fSelectionChangedListeners.add(listener); } @Override public void removeSelectionChangedListener(ISelectionChangedListener listener) { fSelectionChangedListeners.remove(listener); } @Override public void addPostSelectionChangedListener(ISelectionChangedListener listener) { fPostSelectionChangedListeners.add(listener); } @Override public void removePostSelectionChangedListener(ISelectionChangedListener listener) { fPostSelectionChangedListeners.remove(listener); } @Override public ISelection getSelection() { if (fViewerInFocus != null) { return fViewerInFocus.getSelection(); } return TextSelection.emptySelection(); } @Override public void setSelection(ISelection selection) { setSelection(selection, true); } public void setSelection(ISelection selection, boolean reveal) { if (fViewerInFocus != null) { if (reveal && !isSelectionInsideVisibleRegion(fViewerInFocus, selection)) resetVisibleRegion(); fViewerInFocus.setSelection(selection, reveal); } } /** * Resets the visible region for all text viewers of this selection provider. * * @since 3.6 */ private void resetVisibleRegion() { if (fViewers == null) return; for (int i= 0; i < fViewers.length; i++) fViewers[i].setVisibleRegion(0, fViewers[i].getDocument().getLength()); } /** * Tells whether the given selection is inside the text viewer's visible region. * * @param textViewer the text viewer * @param selection the selection * @return true if the selection is inside the text viewer's visible region * @since 3.6 */ private static boolean isSelectionInsideVisibleRegion(TextViewer textViewer, ISelection selection) { if (!(selection instanceof ITextSelection)) return false; ITextSelection textSelection= (ITextSelection)selection; IRegion visibleRegion= textViewer.getVisibleRegion(); return textSelection.getOffset() >= visibleRegion.getOffset() && textSelection.getOffset() + textSelection.getLength() <= visibleRegion.getOffset() + visibleRegion.getLength(); } }