1 /************************************************************** 2 * 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * 20 *************************************************************/ 21 22 package org.apache.openoffice.ooxml.viewer.tokenview; 23 24 import java.awt.Color; 25 import java.awt.Container; 26 import java.awt.Font; 27 import java.awt.FontMetrics; 28 import java.awt.Graphics; 29 import java.awt.Graphics2D; 30 import java.awt.Point; 31 import java.awt.RenderingHints; 32 import java.awt.event.ComponentEvent; 33 import java.awt.event.ComponentListener; 34 import java.awt.event.MouseEvent; 35 import java.awt.event.MouseMotionListener; 36 import java.util.Iterator; 37 import java.util.Vector; 38 39 import javax.swing.JPanel; 40 import javax.swing.JScrollPane; 41 import javax.swing.UIManager; 42 43 /** A simple view of tokenized content. 44 * 45 * Create the content by calling GetDocumentFactory() and using the returned 46 * factory to add tokenized text. 47 */ 48 @SuppressWarnings("serial") 49 public class TokenView<TokenType> 50 extends JPanel 51 implements MouseMotionListener, DocumentFactory.IRepaintTarget, ComponentListener 52 { TokenView()53 public TokenView () 54 { 55 maLines = new LineContainer<TokenType>(); 56 maFormatter = new Formatter<TokenType>(); 57 58 addMouseMotionListener(this); 59 addComponentListener(this); 60 } 61 62 63 64 65 @Override paintComponent(final Graphics aGraphics)66 public void paintComponent (final Graphics aGraphics) 67 { 68 super.paintComponent(aGraphics); 69 70 final Graphics2D aG2 = (Graphics2D)aGraphics; 71 aG2.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); 72 73 final FormatState<TokenType> aState; 74 synchronized(maLines) 75 { 76 aState = maFormatter.FormatText(aG2, maLines); 77 } 78 setPreferredSize(aState.GetTextBoundingSize()); 79 80 for (final Line<TokenType> aLine : aState) 81 { 82 PaintLineHighlight(aG2, aLine); 83 PaintLineNumber(aG2, aLine); 84 85 int nX = mnTextStart; 86 for (final Run<TokenType> aRun : aLine) 87 { 88 final Color aRunColor; 89 if (aRun == maRunUnderMouse) 90 aRunColor = maRunUnderMouseColor; 91 else if (aRun == maHighlightedErrorRun) 92 aRunColor = maErrorHighlightColor; 93 else 94 aRunColor = null; 95 aRun.Paint( 96 (Graphics2D)aGraphics, 97 nX, 98 aLine.GetBottom(), 99 aRunColor); 100 101 nX += aRun.GetWidth(); 102 } 103 } 104 105 aGraphics.setColor(maSeparatorColor); 106 107 final int nTop = aGraphics.getClipBounds().y; 108 final int nBottom = aGraphics.getClipBounds().y+aGraphics.getClipBounds().height; 109 aGraphics.drawLine( 110 mnBarPosition0, 111 nTop, 112 mnBarPosition0, 113 nBottom); 114 aGraphics.drawLine( 115 mnBarPosition1, 116 nTop, 117 mnBarPosition1, 118 nBottom); 119 } 120 121 122 123 124 /** Paint a line with a highlight. 125 * There are different kinds of highlight: 126 * - the current line 127 * - one of three groups of enclosing parent elements 128 */ PaintLineHighlight( final Graphics2D aG2, final Line<TokenType> aLine)129 private void PaintLineHighlight ( 130 final Graphics2D aG2, 131 final Line<TokenType> aLine) 132 { 133 final Color aBackgroundColor; 134 if (aLine == maHighlightedLine) 135 aBackgroundColor = maHighlightColor; 136 else 137 aBackgroundColor = maBackgroundColor; 138 139 final Color aBarColor; 140 if (maLines.IsLineInGroup(aLine, maHighlightedGroup0)) 141 aBarColor = maGroupHighlightColor0; 142 else if (maLines.IsLineInGroup(aLine, maHighlightedGroup1)) 143 aBarColor = maGroupHighlightColor1; 144 else if (maLines.IsLineInGroup(aLine, maHighlightedGroup2)) 145 aBarColor = maGroupHighlightColor2; 146 else 147 aBarColor = maBackgroundColor; 148 149 aG2.setColor(aBarColor); 150 aG2.fillRect( 151 0, 152 aLine.GetTop(), 153 mnLeftBarWidth, 154 aLine.GetHeight()); 155 156 aG2.setColor(aBackgroundColor); 157 aG2.fillRect( 158 mnLeftBarWidth, 159 aLine.GetTop(), 160 getWidth() - mnLeftBarWidth, 161 aLine.GetHeight()); 162 } 163 164 165 166 PaintLineNumber( final Graphics2D aG2, final Line<TokenType> aLine)167 private void PaintLineNumber ( 168 final Graphics2D aG2, 169 final Line<TokenType> aLine) 170 { 171 final String sNumber = Integer.toString(aLine.GetStartOffset()); 172 final FontMetrics aMetrics = aG2.getFontMetrics(); 173 final int nWidth = aMetrics.stringWidth(sNumber); 174 final int nHeight = aMetrics.getHeight(); 175 176 aG2.setColor(maLineNumberColor); 177 aG2.setFont(maLineNumberFont); 178 aG2.drawString( 179 sNumber, 180 mnBarPosition0+1 + mnNumberBarWidth-nWidth, 181 aLine.GetBottom() - (aLine.GetHeight()-nHeight)/2 - aMetrics.getDescent()); 182 } 183 184 185 186 187 @Override mouseDragged(final MouseEvent aEvent)188 public void mouseDragged (final MouseEvent aEvent) 189 { 190 } 191 192 193 194 195 @Override mouseMoved(final MouseEvent aEvent)196 public void mouseMoved (final MouseEvent aEvent) 197 { 198 final Line<TokenType> aLine = maLines.GetLineForY(aEvent.getY()); 199 if (aLine != null) 200 { 201 UpdateHighlightedLine(aLine); 202 final Run<TokenType> aRun = aLine.GetRunForX(aEvent.getX() - mnTextStart); 203 SetRunUnderMouse(aRun); 204 } 205 } 206 207 208 209 UpdateHighlightedLine(final Line<TokenType> aLine)210 private void UpdateHighlightedLine (final Line<TokenType> aLine) 211 { 212 HighlightLine(aLine); 213 214 final Iterator<Run<TokenType>> aRunIterator = aLine.iterator(); 215 if (aRunIterator.hasNext()) 216 { 217 final Run<TokenType> aRun = aRunIterator.next(); 218 if (aRun.IsGroup()) 219 HighlightGroup(aRun); 220 else 221 HighlightGroup(aRun.GetParent()); 222 } 223 } 224 225 226 227 228 @Override RequestRepaint()229 public void RequestRepaint() 230 { 231 repaint(); 232 } 233 234 235 236 GetDocumentFactory()237 public DocumentFactory<TokenType> GetDocumentFactory() 238 { 239 return new DocumentFactory<TokenType>(maLines, this); 240 } 241 242 243 244 HighlightLine(final Line<TokenType> aLine)245 private void HighlightLine (final Line<TokenType> aLine) 246 { 247 if (aLine != maHighlightedLine) 248 { 249 maHighlightedLine = aLine; 250 repaint(); 251 } 252 } 253 254 255 256 HighlightGroup(final Run<TokenType> aRun)257 private void HighlightGroup (final Run<TokenType> aRun) 258 { 259 if (maHighlightedGroup0 != aRun) 260 { 261 maHighlightedGroup0 = aRun; 262 263 if (aRun != null) 264 { 265 final Run<TokenType> aGroup1 = aRun.GetParent(); 266 maHighlightedGroup1 = aGroup1; 267 268 if (aGroup1 != null) 269 { 270 final Run<TokenType> aGroup2 = aGroup1.GetParent(); 271 maHighlightedGroup2 = aGroup2; 272 } 273 } 274 repaint(); 275 } 276 } 277 278 279 280 281 @Override componentHidden(ComponentEvent e)282 public void componentHidden(ComponentEvent e) 283 { 284 } 285 286 287 288 289 @Override componentMoved(final ComponentEvent aEvent)290 public void componentMoved (final ComponentEvent aEvent) 291 { 292 final Point aPoint = getMousePosition(); 293 if (aPoint != null) 294 UpdateHighlightedLine(maLines.GetLineForY(aPoint.y)); 295 } 296 297 298 299 300 @Override componentResized(ComponentEvent e)301 public void componentResized(ComponentEvent e) 302 { 303 } 304 305 306 307 308 @Override componentShown(ComponentEvent e)309 public void componentShown(ComponentEvent e) 310 { 311 } 312 313 314 315 GetRun(final int nOffset)316 public Run<TokenType> GetRun (final int nOffset) 317 { 318 final Line<TokenType> aLine = maLines.GetLineForOffset(nOffset); 319 if (aLine != null) 320 return aLine.GetRunForOffset(nOffset); 321 else 322 return null; 323 } 324 325 326 327 328 /** Return all runs that completely or partially lie in the range from 329 * start offset (including) and end offset (excluding). 330 */ GetRuns(final int nStartOffset, final int nEndOffset)331 public RunRange<TokenType> GetRuns (final int nStartOffset, final int nEndOffset) 332 { 333 final Vector<Run<TokenType>> aRuns = new Vector<>(); 334 335 for (final Line<TokenType> aLine : maLines.GetLinesForOffsets(nStartOffset, nEndOffset)) 336 for (final Run<TokenType> aRun : aLine.GetRunsForOffsets(nStartOffset, nEndOffset)) 337 aRuns.add(aRun); 338 339 return new RunRange<TokenType>(aRuns); 340 } 341 342 343 344 MarkError(final Run<TokenType> aRun)345 public void MarkError (final Run<TokenType> aRun) 346 { 347 maHighlightedErrorRun = aRun; 348 repaint(); 349 } 350 351 352 353 ShowRun(final Run<TokenType> aRun)354 public void ShowRun (final Run<TokenType> aRun) 355 { 356 final Container aComponent = getParent().getParent(); 357 if (aComponent instanceof JScrollPane) 358 ((JScrollPane)aComponent).getVerticalScrollBar().setValue( 359 aRun.GetLine().GetTop()); 360 } 361 362 363 364 SetRunUnderMouse(final Run<TokenType> aRun)365 private void SetRunUnderMouse (final Run<TokenType> aRun) 366 { 367 if (maRunUnderMouse != aRun) 368 { 369 maRunUnderMouse = aRun; 370 if (maRunUnderMouse != null) 371 setToolTipText(maRunUnderMouse.GetToolTipText()); 372 else 373 setToolTipText(null); 374 repaint(); 375 } 376 } 377 378 379 380 381 private final LineContainer<TokenType> maLines; 382 private final Formatter<TokenType> maFormatter; 383 private Line<TokenType> maHighlightedLine; 384 private Run<TokenType> maHighlightedGroup0; 385 private Run<TokenType> maHighlightedGroup1; 386 private Run<TokenType> maHighlightedGroup2; 387 private Run<TokenType> maHighlightedErrorRun; 388 private Run<TokenType> maRunUnderMouse; 389 390 private final static int mnLeftBarWidth = 10; 391 private final static int mnNumberBarWidth = 30; 392 private final static int mnBarPosition0 = mnLeftBarWidth; 393 private final static int mnBarPosition1 = mnBarPosition0 + mnNumberBarWidth ; 394 private final static int mnTextStart = mnBarPosition1 + 2; 395 private final static Color maSeparatorColor = Color.GRAY; 396 private final static Color maBackgroundColor = Color.WHITE; 397 private final static Color maHighlightColor = new Color(0xB0E0E6); // Powder Blue 398 private final static Color maGroupHighlightColor0 = new Color(0x32CD32); // Lime Green 399 private final static Color maGroupHighlightColor1 = new Color(0x90EE90); // Light Green 400 private final static Color maGroupHighlightColor2 = new Color(0xbbFfbb); 401 private final static Color maErrorHighlightColor = new Color(0xff3020); 402 private final static Color maLineNumberColor = new Color(0x808080); 403 private final static Color maRunUnderMouseColor = maGroupHighlightColor2; 404 private final static Font maLineNumberFont = UIManager.getDefaults().getFont("TextField.font").deriveFont(9.0f); 405 406 } 407