Java tutorial
/******************************************************************************* * Copyright (c) 2000, 2004 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.cfeclipse.cfml.editors.decoration; import org.cfeclipse.cfml.CFMLPlugin; import org.cfeclipse.cfml.preferences.EditorPreferenceConstants; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.preference.PreferenceConverter; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IPaintPositionManager; import org.eclipse.jface.text.IPainter; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewerExtension5; import org.eclipse.jface.text.Position; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.source.ICharacterPairMatcher; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.StyledText; import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.PaintListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.FontData; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.RGB; import org.eclipse.ui.internal.editors.text.EditorsPlugin; /** * Highlights the peer character matching the character near the caret position. * This painter can be configured with an * {@link org.eclipse.jface.text.source.ICharacterPairMatcher}. * <p> * Clients instantiate and configure object of this class. * * @since 2.1 */ public final class MatchingCharacterPainter implements IPainter, PaintListener { /** Indicates whether this painter is active */ private boolean fIsActive = false; /** The source viewer this painter is associated with */ private ISourceViewer fSourceViewer; /** The viewer's widget */ private StyledText fTextWidget; /** The color in which to highlight the peer character */ private Color fColor; /** The paint position manager */ private IPaintPositionManager fPaintPositionManager; /** The strategy for finding matching characters */ private ICharacterPairMatcher fMatcher; /** The position tracking the matching characters */ private Position fPairPosition = new Position(0, 0); /** The anchor indicating whether the character is left or right of the caret */ private int fAnchor; /** * Creates a new MatchingCharacterPainter for the given source viewer using * the given character pair matcher. The character matcher is not adopted by * this painter. Thus, it is not disposed. However, this painter requires * exclusive access to the given pair matcher. * * @param sourceViewer * @param matcher */ public MatchingCharacterPainter(ISourceViewer sourceViewer, ICharacterPairMatcher matcher) { fSourceViewer = sourceViewer; fMatcher = matcher; fTextWidget = sourceViewer.getTextWidget(); } /** * Sets the color in which to highlight the match character. * * @param color the color */ public void setColor(Color color) { fColor = color; } /* * @see org.eclipse.jface.text.IPainter#dispose() */ public void dispose() { if (fMatcher != null) { fMatcher.clear(); fMatcher = null; } fColor = null; fTextWidget = null; } /* * @see org.eclipse.jface.text.IPainter#deactivate(boolean) */ public void deactivate(boolean redraw) { if (fIsActive) { fIsActive = false; fTextWidget.removePaintListener(this); if (fPaintPositionManager != null) fPaintPositionManager.unmanagePosition(fPairPosition); if (redraw) handleDrawRequest(null); } } /* * @see org.eclipse.swt.events.PaintListener#paintControl(org.eclipse.swt.events.PaintEvent) */ public void paintControl(PaintEvent event) { if (fTextWidget != null) handleDrawRequest(event.gc); } /** * Handles a redraw request. * * @param gc the GC to draw into. */ private void handleDrawRequest(GC gc) { if (fPairPosition.isDeleted) return; int offset = fPairPosition.getOffset(); int length = fPairPosition.getLength(); if (length < 1) return; if (fSourceViewer instanceof ITextViewerExtension5) { ITextViewerExtension5 extension = (ITextViewerExtension5) fSourceViewer; IRegion widgetRange = extension.modelRange2WidgetRange(new Region(offset, length)); if (widgetRange == null) return; try { // don't draw if the pair position is really hidden and widgetRange just // marks the coverage around it. IDocument doc = fSourceViewer.getDocument(); int startLine = doc.getLineOfOffset(offset); int endLine = doc.getLineOfOffset(offset + length); if (extension.modelLine2WidgetLine(startLine) == -1 || extension.modelLine2WidgetLine(endLine) == -1) return; } catch (BadLocationException e) { return; } offset = widgetRange.getOffset(); length = widgetRange.getLength(); } else { IRegion region = fSourceViewer.getVisibleRegion(); if (region.getOffset() > offset || region.getOffset() + region.getLength() < offset + length) return; offset -= region.getOffset(); } int endOffset = offset + length - 1; draw(gc, offset, 1); draw(gc, endOffset, 1); } /** * Highlights the given widget region. * * @param gc the GC to draw into * @param offset the offset of the widget region * @param length the length of the widget region */ private void draw(GC gc, int offset, int length) { if (gc != null) { Point left = fTextWidget.getLocationAtOffset(offset); Point right = fTextWidget.getLocationAtOffset(offset + length); IPreferenceStore store = CFMLPlugin.getDefault().getPreferenceStore(); int style = store.getInt(EditorPreferenceConstants.P_BRACKET_MATCHING_STYLE); switch (style) { case EditorPreferenceConstants.BRACKET_MATCHING_OUTLINE: { //draw box around character gc.setForeground(fColor); gc.drawRectangle(left.x, left.y, right.x - left.x - 1, fTextWidget.getLineHeight() - 1); break; } case EditorPreferenceConstants.BRACKET_MATCHING_BACKGROUND: { //Paint a background on the character gc.setBackground(fColor); gc.drawText(fTextWidget.getText(offset, offset), left.x, left.y + 1); break; } case EditorPreferenceConstants.BRACKET_MATCHING_BOLD: { int caret = fTextWidget.getCaretOffset(); int lineIndex = fTextWidget.getLineAtOffset(caret); int lineStart = fTextWidget.getOffsetAtLine(lineIndex); int lineEnd = -1; if (lineIndex == fTextWidget.getLineCount()) { lineEnd = fTextWidget.getText().length() - 1; } else { lineEnd = fTextWidget.getText().indexOf(fTextWidget.getLineDelimiter(), lineStart); } if (offset >= lineStart && offset <= lineEnd) { RGB rgb = PreferenceConverter.getColor(store, EditorPreferenceConstants.P_CURRENT_LINE_COLOR); Color c = EditorsPlugin.getDefault().getSharedTextColors().getColor(rgb); gc.setBackground(c); } else { gc.setBackground(fTextWidget.getBackground()); } gc.setForeground(fColor); Font oldFont = gc.getFont(); FontData[] data = gc.getFont().getFontData(); data[0].setStyle(SWT.BOLD); Font font = new Font(fTextWidget.getDisplay(), data); gc.setFont(font); gc.drawText(fTextWidget.getText(offset, offset), left.x, left.y + 1); gc.setFont(oldFont); font.dispose(); break; } } } else { fTextWidget.redrawRange(offset, length, true); } } /* * @see org.eclipse.jface.text.IPainter#paint(int) */ public void paint(int reason) { IDocument document = fSourceViewer.getDocument(); if (document == null) { deactivate(false); return; } Point selection = fSourceViewer.getSelectedRange(); if (selection.y > 0) { deactivate(true); return; } IRegion pair = fMatcher.match(document, selection.x); if (pair == null) { deactivate(true); return; } if (fIsActive) { if (IPainter.CONFIGURATION == reason) { // redraw current highlighting handleDrawRequest(null); } else if (pair.getOffset() != fPairPosition.getOffset() || pair.getLength() != fPairPosition.getLength() || fMatcher.getAnchor() != fAnchor) { // otherwise only do something if position is different // remove old highlighting handleDrawRequest(null); // update position fPairPosition.isDeleted = false; fPairPosition.offset = pair.getOffset(); fPairPosition.length = pair.getLength(); fAnchor = fMatcher.getAnchor(); // apply new highlighting handleDrawRequest(null); } } else { fIsActive = true; fPairPosition.isDeleted = false; fPairPosition.offset = pair.getOffset(); fPairPosition.length = pair.getLength(); fAnchor = fMatcher.getAnchor(); fTextWidget.addPaintListener(this); fPaintPositionManager.managePosition(fPairPosition); handleDrawRequest(null); } } /* * @see org.eclipse.jface.text.IPainter#setPositionManager(org.eclipse.jface.text.IPaintPositionManager) */ public void setPositionManager(IPaintPositionManager manager) { fPaintPositionManager = manager; } }