Java tutorial
/******************************************************************************* * Copyright (c) 2000, 2015 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.ui.editors.text.overview; import java.lang.ref.WeakReference; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CaretEvent; import org.eclipse.swt.custom.CaretListener; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.custom.TextChangeListener; import org.eclipse.swt.custom.TextChangedEvent; import org.eclipse.swt.custom.TextChangingEvent; import org.eclipse.swt.events.ControlAdapter; import org.eclipse.swt.events.ControlEvent; import org.eclipse.swt.events.ControlListener; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseTrackAdapter; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Cursor; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Scale; import org.eclipse.swt.widgets.Scrollable; import org.eclipse.jface.window.DefaultToolTip; import org.eclipse.jface.window.ToolTip; import org.eclipse.jface.text.JFaceTextUtil; import org.eclipse.ui.ISizeProvider; import org.eclipse.ui.internal.editors.text.EditorsPlugin; import org.eclipse.ui.part.ViewPart; /** * This implements a view that shows the overview of last focused StyledText in the parent workbench * windows * * @author Sandip Chitale */ public class OverviewView extends ViewPart implements ISizeProvider { /** * The ID of the view as specified by the extension. */ public static final String ID = "org.eclipse.ui.editors.text.overview.OverviewView"; //$NON-NLS-1$ private StyledText overviewStyledText; private Cursor overviewStyledTextCrosshairCursor; private DefaultToolTip overviewStyledTextToolTip; private StyledText lastOverviewedStyledText; private Font lastFont; private String lastFontName; private int lastFontStyle; private double lastScale = 0.2d; private int lastTopIndex = -1; private int lastLineAtOffset = -1; private Listener focusListenerFilter; private ControlListener parentResizeListener; private TextChangeListener lastOverviewedStyledTextTextChangeListener; private CaretListener lastOverviewedStyledTextCaretListener; private SelectionListener lastOverviewedStyledTextScrollBarSelectionListener; private ControlListener lastOverviewedStyledTextResizeListener; private DisposeListener lastOverviewedStyledTextDisposeListener; private final ThreadLocal<Boolean> suspendLastOverviewedStyledText = new ThreadLocal<>(); private Scale scale; /** * The constructor. */ public OverviewView() { } /** * This is a callback that will allow us to create the viewer and initialize it. */ @Override public void createPartControl(Composite parent) { final Display display = parent.getDisplay(); Composite container = new Composite(parent, SWT.NONE); container.setLayout(new org.eclipse.swt.layout.GridLayout(1, true)); final Composite composite = new Composite(container, SWT.NONE); composite.setLayout(null); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); lastOverviewedStyledTextTextChangeListener = new TextChangeListener() { @Override public void textSet(TextChangedEvent event) { /*Empty*/} @Override public void textChanging(TextChangingEvent event) { blank(); } @Override public void textChanged(TextChangedEvent event) { blank(); } }; // listener to monitor if the caret movement changed the // lines visible in the tracked StyledText due to scrolling lastOverviewedStyledTextCaretListener = new CaretListener() { @Override public void caretMoved(CaretEvent event) { if (suspendLastOverviewedStyledText.get() != null) { return; } int topIndex = -1; int lineAtOffset = -1; try { if (lastOverviewedStyledText != null) { topIndex = lastOverviewedStyledText.getTopIndex(); int caretOffset = lastOverviewedStyledText.getCaretOffset(); lineAtOffset = lastOverviewedStyledText.getLineAtOffset(caretOffset); if (topIndex != lastTopIndex || lineAtOffset != lastLineAtOffset) { highlightViewport(topIndex != lastTopIndex); } } } finally { lastTopIndex = topIndex; lastLineAtOffset = lineAtOffset; } } }; lastOverviewedStyledTextScrollBarSelectionListener = new SelectionAdapter() { @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } @Override public void widgetSelected(SelectionEvent event) { if (suspendLastOverviewedStyledText.get() != null) { return; } int topIndex = -1; int lineAtOffset = -1; try { if (lastOverviewedStyledText != null) { topIndex = lastOverviewedStyledText.getTopIndex(); int caretOffset = lastOverviewedStyledText.getCaretOffset(); lineAtOffset = lastOverviewedStyledText.getLineAtOffset(caretOffset); if (topIndex != lastTopIndex || lineAtOffset != lastLineAtOffset) { highlightViewport(topIndex != lastTopIndex); } } } finally { lastTopIndex = topIndex; lastLineAtOffset = lineAtOffset; } } }; lastOverviewedStyledTextResizeListener = new ControlAdapter() { @Override public void controlResized(ControlEvent e) { adjustSize(); } }; // listener for dispose of tracked StyledText lastOverviewedStyledTextDisposeListener = new DisposeListener() { @Override public void widgetDisposed(DisposeEvent e) { blank(); } }; focusListenerFilter = new Listener() { @Override public void handleEvent(final Event event) { OverviewView.this.handleEvent(event); } }; display.syncExec(new Runnable() { @Override public void run() { // Track focus display.addFilter(SWT.FocusIn, focusListenerFilter); } }); scale = new Scale(container, SWT.BORDER); scale.setMinimum(getMinOverviewFontSize()); scale.setSelection(getOverviewFontSize()); scale.setMaximum(getMaxOverviewFontSize()); scale.setIncrement(1); scale.setPageIncrement(1); scale.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); scale.addSelectionListener(new SelectionListener() { @Override public void widgetSelected(SelectionEvent e) { adjustFontSize(composite); } @Override public void widgetDefaultSelected(SelectionEvent e) { widgetSelected(e); } }); reconfigureOverviewStyledText(composite); } private void adjustFontSize(Composite composite) { setOverviewFontSize(scale.getSelection()); StyledText styledText = lastOverviewedStyledText; blank(); lastFontName = null; lastFontStyle = 0; reconfigureOverviewStyledText(composite); lastOverviewedStyledText = null; trackStyledText(styledText); } void changeFontSize(String increaseOrDecrease) { int selection = scale.getSelection(); if (FontSizeParameterValues.DECREASE.equals(increaseOrDecrease)) { if (selection > getMinOverviewFontSize()) { selection--; scale.setSelection(selection); adjustFontSize(overviewStyledText.getParent()); } } else if (FontSizeParameterValues.INCREASE.equals(increaseOrDecrease)) { if (selection < getMaxOverviewFontSize()) { selection++; scale.setSelection(selection); adjustFontSize(overviewStyledText.getParent()); } } } private void reconfigureOverviewStyledText(Composite composite) { final Display display = composite.getDisplay(); boolean layout = false; if (overviewStyledText != null) { overviewStyledTextToolTip.hide(); overviewStyledText.setToolTipText(null); removeListenersLastOverviewedStyledText(); overviewStyledTextCrosshairCursor.dispose(); overviewStyledText.dispose(); layout = true; } overviewStyledText = new StyledText(composite, SWT.MULTI | SWT.READ_ONLY | SWT.V_SCROLL | SWT.H_SCROLL); overviewStyledText.setEditable(false); overviewStyledTextCrosshairCursor = new Cursor(display, SWT.CURSOR_CROSS); overviewStyledText.setCursor(overviewStyledTextCrosshairCursor); overviewStyledTextToolTip = new DefaultToolTip(overviewStyledText, ToolTip.RECREATE, true); overviewStyledText.addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { if (lastOverviewedStyledText != null) { overviewStyledTextToolTip.hide(); lastOverviewedStyledText.setFocus(); } } }); overviewStyledText.addMouseTrackListener(new MouseTrackAdapter() { @Override public void mouseHover(MouseEvent e) { int lineIndex = overviewStyledText.getLineIndex(e.y); int fromLine = Math.max(0, lineIndex - 2); int toLine = Math.min(overviewStyledText.getLineCount() - 1, lineIndex + 2); int width = (int) (Math.log10(toLine + 1) + 2); StringBuilder tooltip = new StringBuilder(); for (int i = fromLine; i <= toLine; i++) { if (i > fromLine) { tooltip.append("\n"); //$NON-NLS-1$ } tooltip.append(String.format("%" + width + "d ", Integer.valueOf(i + 1))); //$NON-NLS-1$ //$NON-NLS-2$ String line = overviewStyledText.getLine(i); if (line != null) { tooltip.append((i == lineIndex ? "\u00bb" : " ") + "\t" + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ line.substring(0, Math.min(line.length(), 80))); } } overviewStyledTextToolTip.setText(tooltip.toString()); overviewStyledTextToolTip.setPopupDelay(500); overviewStyledTextToolTip.setHideDelay(3000); overviewStyledTextToolTip.show(new Point(0, e.y + 10)); } @Override public void mouseExit(MouseEvent e) { overviewStyledTextToolTip.setText(null); } }); overviewStyledText.addCaretListener(new CaretListener() { @Override public void caretMoved(CaretEvent event) { if (suspendLastOverviewedStyledText.get() != null) { return; } adjustTrackedStyledText(); } }); parentResizeListener = new ControlAdapter() { @Override public void controlResized(ControlEvent e) { adjustSize(); } }; overviewStyledText.getParent().addControlListener(parentResizeListener); display.syncExec(new Runnable() { @Override public void run() { // Check if there is focused StyledText // in this workbench window, if so track it Control focusControl = display.getFocusControl(); if (focusControl instanceof StyledText) { StyledText styledText = (StyledText) focusControl; if (styledText.getShell() == overviewStyledText.getShell()) { trackStyledText(styledText); } } } }); if (layout) { composite.layout(true); } } private WeakReference<StyledText> lastNonOverviewStyledText = null; void refreshOverviewView() { if (lastNonOverviewStyledText != null) { StyledText st = lastNonOverviewStyledText.get(); if (st == null || st.isDisposed()) { lastNonOverviewStyledText = null; return; } trackStyledText(st); } } protected void handleEvent(Event event) { if (event.type == SWT.FocusIn) { if (event.widget instanceof StyledText) { StyledText styledText = (StyledText) event.widget; if (styledText.isDisposed()) { return; } if (styledText == overviewStyledText) { refreshOverviewView(); return; } if (styledText.getShell() != overviewStyledText.getShell()) { return; } lastNonOverviewStyledText = new WeakReference<>(styledText); trackStyledText(styledText); } } } @Override public void dispose() { overviewStyledTextCrosshairCursor.dispose(); getViewSite().getWorkbenchWindow().getShell().getDisplay().removeFilter(SWT.FocusIn, focusListenerFilter); removeListenersLastOverviewedStyledText(); lastOverviewedStyledText = null; if (lastFont != null) { lastFont.dispose(); lastFont = null; } lastFontName = null; focusListenerFilter = null; super.dispose(); } private void trackStyledText(StyledText styledText) { if (lastOverviewedStyledText == styledText) { return; } removeListenersLastOverviewedStyledText(); try { suspendLastOverviewedStyledText.set(Boolean.TRUE); lastOverviewedStyledText = styledText; addListenersLastOverviewedStyledText(); Font font = lastOverviewedStyledText.getFont(); FontData[] fontData = font.getFontData(); FontData fontDatum = fontData[0]; if (fontDatum.getName().equals(lastFontName) && fontDatum.getStyle() == lastFontStyle) { // nothing to do } else { lastFontName = fontDatum.getName(); lastFontStyle = fontDatum.getStyle(); if (lastFont != null) { lastFont.dispose(); } lastFont = new Font(overviewStyledText.getDisplay(), lastFontName, getOverviewFontSize(), lastFontStyle); lastScale = ((double) getOverviewFontSize()) / ((double) fontDatum.getHeight()); overviewStyledText.setFont(lastFont); overviewStyledTextToolTip.setFont(font); } overviewStyledText.setForeground(lastOverviewedStyledText.getForeground()); overviewStyledText.setBackground(lastOverviewedStyledText.getBackground()); overviewStyledTextToolTip.setForegroundColor(lastOverviewedStyledText.getForeground()); overviewStyledTextToolTip.setBackgroundColor(lastOverviewedStyledText.getBackground()); overviewStyledText.setSelectionForeground(lastOverviewedStyledText.getSelectionForeground()); overviewStyledText.setSelectionBackground(lastOverviewedStyledText.getSelectionBackground()); overviewStyledText.setText(lastOverviewedStyledText.getText()); overviewStyledText.setStyleRanges(lastOverviewedStyledText.getStyleRanges()); overviewStyledText.setSelection(lastOverviewedStyledText.getSelection()); scale.setToolTipText("Overview font size: " + getOverviewFontSize()); //$NON-NLS-1$ adjustSize(); highlightViewport(true); } finally { suspendLastOverviewedStyledText.set(null); } } private void removeListenersLastOverviewedStyledText() { if (lastOverviewedStyledText != null) { lastOverviewedStyledText.getContent() .removeTextChangeListener(lastOverviewedStyledTextTextChangeListener); lastOverviewedStyledText.removeCaretListener(lastOverviewedStyledTextCaretListener); lastOverviewedStyledText.removeControlListener(lastOverviewedStyledTextResizeListener); lastOverviewedStyledText.removeDisposeListener(lastOverviewedStyledTextDisposeListener); ((Scrollable) lastOverviewedStyledText).getVerticalBar() .removeSelectionListener(lastOverviewedStyledTextScrollBarSelectionListener); } } private void addListenersLastOverviewedStyledText() { if (lastOverviewedStyledText != null) { lastOverviewedStyledText.getContent().addTextChangeListener(lastOverviewedStyledTextTextChangeListener); lastOverviewedStyledText.addCaretListener(lastOverviewedStyledTextCaretListener); lastOverviewedStyledText.addControlListener(lastOverviewedStyledTextResizeListener); lastOverviewedStyledText.addDisposeListener(lastOverviewedStyledTextDisposeListener); ((Scrollable) lastOverviewedStyledText).getVerticalBar() .addSelectionListener(lastOverviewedStyledTextScrollBarSelectionListener); } } private void blank() { removeListenersLastOverviewedStyledText(); lastOverviewedStyledText = null; lastTopIndex = -1; lastLineAtOffset = -1; overviewStyledText.setForeground(null); overviewStyledText.setBackground(null); overviewStyledTextToolTip.setForegroundColor(null); overviewStyledTextToolTip.setBackgroundColor(null); overviewStyledText.setSelectionForeground(null); overviewStyledText.setSelectionBackground(null); overviewStyledText.setText(""); //$NON-NLS-1$ overviewStyledText.setStyleRanges(new StyleRange[0]); adjustSize(); unhighlightViewport(); } private void adjustSize() { Point size = overviewStyledText.computeSize(SWT.DEFAULT, SWT.DEFAULT); int x = (int) (size.x * lastScale); Point parentSize = overviewStyledText.getParent().getSize(); overviewStyledText.setSize(new Point(Math.max(parentSize.x, x), parentSize.y)); } private void unhighlightViewport() { overviewStyledText.setLineBackground(0, overviewStyledText.getLineCount() - 1, null); } private void highlightViewport(boolean topIndexChanged) { if (topIndexChanged) { unhighlightViewport(); } if (lastOverviewedStyledText != null) { // The index of the first (possibly only partially) visible line of // the widget int topIndex = JFaceTextUtil.getPartialTopIndex(lastOverviewedStyledText); // The index of the last (possibly only partially) visible line of // the widget int bottomIndex = JFaceTextUtil.getPartialBottomIndex(lastOverviewedStyledText); int caretOffset = lastOverviewedStyledText.getCaretOffset(); int lineAtOffset = lastOverviewedStyledText.getLineAtOffset(caretOffset); overviewStyledText.setLineBackground(topIndex, (bottomIndex - topIndex) + (bottomIndex >= (overviewStyledText.getLineCount() - 1) ? 0 : 1), overviewStyledText.getSelectionBackground()); overviewStyledText.setLineBackground(lineAtOffset, 1, null); if (suspendLastOverviewedStyledText.get() == null) { if (topIndex == 0) { overviewStyledText.setTopIndex(topIndex); } else { overviewStyledText.setTopIndex(Math.max(0, topIndex - 1)); } } } } private void adjustTrackedStyledText() { if (lastOverviewedStyledText != null) { try { suspendLastOverviewedStyledText.set(Boolean.TRUE); int topIndex = JFaceTextUtil.getPartialTopIndex(lastOverviewedStyledText); // The index of the last (possibly only partially) visible line of // the widget int bottomIndex = JFaceTextUtil.getPartialBottomIndex(lastOverviewedStyledText); int visibleLinesCount = bottomIndex - topIndex; int caretOffset = overviewStyledText.getCaretOffset(); int lineAtOffset = overviewStyledText.getLineAtOffset(caretOffset); lastOverviewedStyledText.setTopIndex(Math.max(0, (lineAtOffset - (visibleLinesCount / 2)))); lastOverviewedStyledText.setCaretOffset(caretOffset); highlightViewport(true); } finally { suspendLastOverviewedStyledText.set(null); } } } /** * Passing the focus request to the viewer's control. */ @Override public void setFocus() { overviewStyledText.setFocus(); } @Override public int getSizeFlags(boolean width) { if (!width) { return SWT.MIN | SWT.MAX; } return 0; } @Override public int computePreferredSize(boolean width, int availableParallel, int availablePerpendicular, int preferredResult) { if (width) { return 140; } return 0; } public static int getMinOverviewFontSize() { return EditorsPlugin.getDefault().getPreferenceStore().getInt(OverviewPreferences.MIN_OVERVIEW_FONT_SIZE); } public static int getOverviewFontSize() { return EditorsPlugin.getDefault().getPreferenceStore().getInt(OverviewPreferences.OVERVIEW_FONT_SIZE); } public static void setOverviewFontSize(int fontSize) { EditorsPlugin.getDefault().getPreferenceStore().setValue(OverviewPreferences.OVERVIEW_FONT_SIZE, Math.min(getMaxOverviewFontSize(), Math.max(fontSize, getMinOverviewFontSize()))); } public static int getMaxOverviewFontSize() { return EditorsPlugin.getDefault().getPreferenceStore().getInt(OverviewPreferences.MAX_OVERVIEW_FONT_SIZE); } }