You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TextPaneCanvas.java 9.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. /*
  2. * Copyright (c) 2006-2007 Chris Smith, Shane Mc Cormack, Gregory Holmes
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  20. * SOFTWARE.
  21. */
  22. package com.dmdirc.ui.textpane;
  23. import java.awt.Canvas;
  24. import java.awt.Color;
  25. import java.awt.Dimension;
  26. import java.awt.Graphics;
  27. import java.awt.Graphics2D;
  28. import java.awt.Image;
  29. import java.awt.Point;
  30. import java.awt.Rectangle;
  31. import java.awt.event.MouseEvent;
  32. import java.awt.event.MouseListener;
  33. import java.awt.event.MouseMotionListener;
  34. import java.awt.font.FontRenderContext;
  35. import java.awt.font.LineBreakMeasurer;
  36. import java.awt.font.TextLayout;
  37. import java.text.AttributedCharacterIterator;
  38. import java.util.HashMap;
  39. import java.util.Map;
  40. import javax.swing.JFrame;
  41. /** Canvas object to draw text. */
  42. class TextPaneCanvas extends Canvas implements MouseListener, MouseMotionListener {
  43. /**
  44. * A version number for this class. It should be changed whenever the
  45. * class structure is changed (or anything else that would prevent
  46. * serialized objects being unserialized with the new class).
  47. */
  48. private static final long serialVersionUID = 2;
  49. /** Font render context to be used for the text in this pane. */
  50. private final FontRenderContext defaultFRC = new FontRenderContext(null, false, false);
  51. /** IRCDocument. */
  52. private IRCDocument document;
  53. /** line break measurer, used for line wrapping. */
  54. private LineBreakMeasurer lineMeasurer;
  55. /** start character of a paragraph. */
  56. private int paragraphStart;
  57. /** end character of a paragraph. */
  58. private int paragraphEnd;
  59. /** position of the scrollbar. */
  60. private int scrollBarPosition;
  61. /** parent textpane. */
  62. private TextPane textPane;
  63. /** Position -> TextLayout. */
  64. private Map<Rectangle, TextLayout> positions;
  65. /** TextLayout -> Line numbers. */
  66. private Map<TextLayout, String> textLayouts;
  67. /** Start line of the selection. */
  68. private int selStartLine;
  69. /** Start character of the selection. */
  70. private int selStartChar;
  71. /** End line of the selection. */
  72. private int selEndLine;
  73. /** End character of the selection. */
  74. private int selEndChar;
  75. /**
  76. * Creates a new text pane canvas.
  77. *
  78. * @param parent parent text pane for the canvas
  79. * @param document IRCDocument to be displayed
  80. */
  81. public TextPaneCanvas(final TextPane parent, final IRCDocument document) {
  82. this.document = document;
  83. scrollBarPosition = 0;
  84. textPane = parent;
  85. textLayouts = new HashMap<TextLayout, String>();
  86. positions = new HashMap<Rectangle, TextLayout>();
  87. this.addMouseListener(this);
  88. this.addMouseMotionListener(this);
  89. }
  90. /**
  91. * Paints the text onto the canvas.
  92. * @param g graphics object to draw onto
  93. */
  94. public void paint(final Graphics g) {
  95. final Graphics2D graphics2D = (Graphics2D) g;
  96. final float formatWidth = getWidth();
  97. final float formatHeight = getHeight();
  98. textLayouts.clear();
  99. positions.clear();
  100. float drawPosY = formatHeight;
  101. int startLine = scrollBarPosition;
  102. if (startLine >= document.getNumLines()) {
  103. startLine = document.getNumLines() - 1;
  104. }
  105. if (startLine <= 0) {
  106. startLine = 0;
  107. }
  108. for (int i = startLine; i >= 0; i--) {
  109. final AttributedCharacterIterator iterator = document.getLine(i).getIterator();
  110. paragraphStart = iterator.getBeginIndex();
  111. paragraphEnd = iterator.getEndIndex();
  112. lineMeasurer = new LineBreakMeasurer(iterator, defaultFRC);
  113. lineMeasurer.setPosition(paragraphStart);
  114. int wrappedLine = 0;
  115. int height = 0;
  116. while (lineMeasurer.getPosition() < paragraphEnd) {
  117. final TextLayout layout = lineMeasurer.nextLayout(formatWidth);
  118. wrappedLine++;
  119. height += layout.getDescent() + layout.getLeading() + layout.getAscent();
  120. }
  121. lineMeasurer.setPosition(paragraphStart);
  122. paragraphStart = iterator.getBeginIndex();
  123. paragraphEnd = iterator.getEndIndex();
  124. if (wrappedLine > 1) {
  125. drawPosY -= height;
  126. }
  127. int j = 0;
  128. while (lineMeasurer.getPosition() < paragraphEnd) {
  129. final TextLayout layout = lineMeasurer.nextLayout(formatWidth);
  130. if (wrappedLine == 1) {
  131. drawPosY -= layout.getDescent() + layout.getLeading() + layout.getAscent();
  132. } else {
  133. if (j != 0) {
  134. drawPosY += layout.getDescent() + layout.getLeading() + layout.getAscent();
  135. }
  136. }
  137. float drawPosX;
  138. if (layout.isLeftToRight()) {
  139. drawPosX = 0;
  140. } else {
  141. drawPosX = formatWidth - layout.getAdvance();
  142. }
  143. if (drawPosY + layout.getAscent() >= 0
  144. || (drawPosY + layout.getDescent() + layout.getLeading()) <= formatHeight) {
  145. layout.draw(graphics2D, drawPosX, drawPosY + layout.getAscent());
  146. textLayouts.put(layout, "" + i + "." + j);
  147. positions.put(new Rectangle(
  148. (int) drawPosX,
  149. (int) drawPosY,
  150. (int) formatHeight,
  151. (int) (layout.getDescent() + layout.getLeading() + layout.getAscent())
  152. ), layout);
  153. }
  154. j++;
  155. }
  156. if (j > 1) {
  157. drawPosY -= height;
  158. }
  159. if (drawPosY <= 0) {
  160. break;
  161. }
  162. }
  163. }
  164. /**
  165. * Repaints the canvas offscreen.
  166. * @param g graphics object to draw onto
  167. */
  168. public void update(final Graphics g) {
  169. final Image offScreen = this.createImage(getWidth(), getHeight());
  170. final Graphics graphics = offScreen.getGraphics();
  171. graphics.clearRect(0, 0, this.getWidth(), this.getHeight());
  172. paint(graphics);
  173. g.drawImage(offScreen, 0, 0, this);
  174. }
  175. /**
  176. * sets the position of the scroll bar, and repaints if required.
  177. * @param position scroll bar position
  178. */
  179. public void setScrollBarPosition(final int position) {
  180. if (scrollBarPosition != position) {
  181. scrollBarPosition = position;
  182. this.repaint();
  183. }
  184. }
  185. /** {@inheritDoc}. */
  186. public void mouseClicked(final MouseEvent e) {
  187. //Ignore
  188. }
  189. /** {@inheritDoc}. */
  190. public void mousePressed(final MouseEvent e) {
  191. int line = -1;
  192. final Point point = this.getMousePosition();
  193. if (point != null) {
  194. String whichLine = "";
  195. for (Map.Entry<Rectangle, TextLayout> entry : positions.entrySet()) {
  196. if (entry.getKey().contains(point)) {
  197. //TODO: parse line and start char
  198. whichLine = textLayouts.get(entry.getValue());
  199. System.out.println(textLayouts.get(entry.getValue()) + " " + entry.getValue().hitTestChar((int) point.getX(), (int) point.getY()).getCharIndex());
  200. }
  201. }
  202. for (Map.Entry<TextLayout, String> entry : textLayouts.entrySet()) {
  203. entry.getValue().matches("");
  204. line = -1;
  205. }
  206. }
  207. }
  208. /** {@inheritDoc}. */
  209. public void mouseReleased(final MouseEvent e) {
  210. //TODO: parse line and end char
  211. }
  212. /** {@inheritDoc}. */
  213. public void mouseEntered(final MouseEvent e) {
  214. //Ignore
  215. }
  216. /** {@inheritDoc}. */
  217. public void mouseExited(final MouseEvent e) {
  218. //Ignore
  219. }
  220. /** {@inheritDoc}. */
  221. public void mouseDragged(final MouseEvent e) {
  222. //TODO: parse line and end char
  223. }
  224. /** {@inheritDoc}. */
  225. public void mouseMoved(final MouseEvent e) {
  226. //Ignore
  227. }
  228. /**
  229. * temporary method to text the textpane.
  230. * @param args command line arguments
  231. */
  232. public static void main(final String[] args) {
  233. final TextPane tpc = new TextPane();
  234. final JFrame frame = new JFrame("Test textpane");
  235. tpc.setDoubleBuffered(true);
  236. tpc.setBackground(Color.WHITE);
  237. frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  238. frame.add(tpc);
  239. frame.setSize(new Dimension(400, 400));
  240. frame.setVisible(true);
  241. tpc.addTestText();
  242. }
  243. }