123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291 |
- /*
- * Copyright (c) 2006-2007 Chris Smith, Shane Mc Cormack, Gregory Holmes
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
- package com.dmdirc.ui.textpane;
-
- import java.awt.Canvas;
- import java.awt.Color;
- import java.awt.Dimension;
- import java.awt.Graphics;
- import java.awt.Graphics2D;
- import java.awt.Image;
- import java.awt.Point;
- import java.awt.Rectangle;
- import java.awt.event.MouseEvent;
- import java.awt.event.MouseListener;
- import java.awt.event.MouseMotionListener;
- import java.awt.font.FontRenderContext;
- import java.awt.font.LineBreakMeasurer;
- import java.awt.font.TextLayout;
- import java.text.AttributedCharacterIterator;
- import java.util.HashMap;
- import java.util.Map;
-
- import javax.swing.JFrame;
-
-
- /** Canvas object to draw text. */
- class TextPaneCanvas extends Canvas implements MouseListener, MouseMotionListener {
-
- /**
- * A version number for this class. It should be changed whenever the
- * class structure is changed (or anything else that would prevent
- * serialized objects being unserialized with the new class).
- */
- private static final long serialVersionUID = 2;
-
- /** Font render context to be used for the text in this pane. */
- private final FontRenderContext defaultFRC = new FontRenderContext(null, false, false);
-
- /** IRCDocument. */
- private IRCDocument document;
-
- /** line break measurer, used for line wrapping. */
- private LineBreakMeasurer lineMeasurer;
-
- /** start character of a paragraph. */
- private int paragraphStart;
- /** end character of a paragraph. */
- private int paragraphEnd;
- /** position of the scrollbar. */
- private int scrollBarPosition;
- /** parent textpane. */
- private TextPane textPane;
-
- /** Position -> TextLayout. */
- private Map<Rectangle, TextLayout> positions;
- /** TextLayout -> Line numbers. */
- private Map<TextLayout, String> textLayouts;
-
- /** Start line of the selection. */
- private int selStartLine;
- /** Start character of the selection. */
- private int selStartChar;
- /** End line of the selection. */
- private int selEndLine;
- /** End character of the selection. */
- private int selEndChar;
-
- /**
- * Creates a new text pane canvas.
- *
- * @param parent parent text pane for the canvas
- * @param document IRCDocument to be displayed
- */
- public TextPaneCanvas(final TextPane parent, final IRCDocument document) {
- this.document = document;
- scrollBarPosition = 0;
- textPane = parent;
- textLayouts = new HashMap<TextLayout, String>();
- positions = new HashMap<Rectangle, TextLayout>();
- this.addMouseListener(this);
- this.addMouseMotionListener(this);
- }
-
- /**
- * Paints the text onto the canvas.
- * @param g graphics object to draw onto
- */
- public void paint(final Graphics g) {
- final Graphics2D graphics2D = (Graphics2D) g;
-
- final float formatWidth = getWidth();
- final float formatHeight = getHeight();
-
- textLayouts.clear();
- positions.clear();
-
- float drawPosY = formatHeight;
-
- int startLine = scrollBarPosition;
- if (startLine >= document.getNumLines()) {
- startLine = document.getNumLines() - 1;
- }
- if (startLine <= 0) {
- startLine = 0;
- }
-
- for (int i = startLine; i >= 0; i--) {
- final AttributedCharacterIterator iterator = document.getLine(i).getIterator();
- paragraphStart = iterator.getBeginIndex();
- paragraphEnd = iterator.getEndIndex();
- lineMeasurer = new LineBreakMeasurer(iterator, defaultFRC);
- lineMeasurer.setPosition(paragraphStart);
-
- int wrappedLine = 0;
- int height = 0;
-
- while (lineMeasurer.getPosition() < paragraphEnd) {
- final TextLayout layout = lineMeasurer.nextLayout(formatWidth);
- wrappedLine++;
- height += layout.getDescent() + layout.getLeading() + layout.getAscent();
- }
-
- lineMeasurer.setPosition(paragraphStart);
- paragraphStart = iterator.getBeginIndex();
- paragraphEnd = iterator.getEndIndex();
-
- if (wrappedLine > 1) {
- drawPosY -= height;
- }
-
- int j = 0;
- while (lineMeasurer.getPosition() < paragraphEnd) {
-
- final TextLayout layout = lineMeasurer.nextLayout(formatWidth);
-
- if (wrappedLine == 1) {
- drawPosY -= layout.getDescent() + layout.getLeading() + layout.getAscent();
- } else {
- if (j != 0) {
- drawPosY += layout.getDescent() + layout.getLeading() + layout.getAscent();
- }
- }
-
- float drawPosX;
- if (layout.isLeftToRight()) {
- drawPosX = 0;
- } else {
- drawPosX = formatWidth - layout.getAdvance();
- }
-
- if (drawPosY + layout.getAscent() >= 0
- || (drawPosY + layout.getDescent() + layout.getLeading()) <= formatHeight) {
- layout.draw(graphics2D, drawPosX, drawPosY + layout.getAscent());
- textLayouts.put(layout, "" + i + "." + j);
- positions.put(new Rectangle(
- (int) drawPosX,
- (int) drawPosY,
- (int) formatHeight,
- (int) (layout.getDescent() + layout.getLeading() + layout.getAscent())
- ), layout);
- }
- j++;
- }
- if (j > 1) {
- drawPosY -= height;
- }
- if (drawPosY <= 0) {
- break;
- }
- }
- }
-
- /**
- * Repaints the canvas offscreen.
- * @param g graphics object to draw onto
- */
- public void update(final Graphics g) {
- final Image offScreen = this.createImage(getWidth(), getHeight());
- final Graphics graphics = offScreen.getGraphics();
-
- graphics.clearRect(0, 0, this.getWidth(), this.getHeight());
-
- paint(graphics);
-
- g.drawImage(offScreen, 0, 0, this);
- }
-
- /**
- * sets the position of the scroll bar, and repaints if required.
- * @param position scroll bar position
- */
- public void setScrollBarPosition(final int position) {
- if (scrollBarPosition != position) {
- scrollBarPosition = position;
- this.repaint();
- }
- }
-
- /** {@inheritDoc}. */
- public void mouseClicked(final MouseEvent e) {
- //Ignore
- }
-
- /** {@inheritDoc}. */
- public void mousePressed(final MouseEvent e) {
- int line = -1;
-
- final Point point = this.getMousePosition();
-
- if (point != null) {
- String whichLine = "";
- for (Map.Entry<Rectangle, TextLayout> entry : positions.entrySet()) {
- if (entry.getKey().contains(point)) {
- //TODO: parse line and start char
- whichLine = textLayouts.get(entry.getValue());
- System.out.println(textLayouts.get(entry.getValue()) + " " + entry.getValue().hitTestChar((int) point.getX(), (int) point.getY()).getCharIndex());
- }
- }
- for (Map.Entry<TextLayout, String> entry : textLayouts.entrySet()) {
- entry.getValue().matches("");
- line = -1;
- }
- }
- }
-
- /** {@inheritDoc}. */
- public void mouseReleased(final MouseEvent e) {
- //TODO: parse line and end char
- }
-
- /** {@inheritDoc}. */
- public void mouseEntered(final MouseEvent e) {
- //Ignore
- }
-
- /** {@inheritDoc}. */
- public void mouseExited(final MouseEvent e) {
- //Ignore
- }
-
- /** {@inheritDoc}. */
- public void mouseDragged(final MouseEvent e) {
- //TODO: parse line and end char
- }
-
- /** {@inheritDoc}. */
- public void mouseMoved(final MouseEvent e) {
- //Ignore
- }
-
- /**
- * temporary method to text the textpane.
- * @param args command line arguments
- */
- public static void main(final String[] args) {
- final TextPane tpc = new TextPane();
- final JFrame frame = new JFrame("Test textpane");
-
- tpc.setDoubleBuffered(true);
- tpc.setBackground(Color.WHITE);
-
- frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
-
- frame.add(tpc);
-
- frame.setSize(new Dimension(400, 400));
- frame.setVisible(true);
-
- tpc.addTestText();
- }
- }
|