mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			725 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			725 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
| /* PlainView.java --
 | |
|    Copyright (C) 2004, 2005, 2006  Free Software Foundation, Inc.
 | |
| 
 | |
| This file is part of GNU Classpath.
 | |
| 
 | |
| GNU Classpath is free software; you can redistribute it and/or modify
 | |
| it under the terms of the GNU General Public License as published by
 | |
| the Free Software Foundation; either version 2, or (at your option)
 | |
| any later version.
 | |
| 
 | |
| GNU Classpath is distributed in the hope that it will be useful, but
 | |
| WITHOUT ANY WARRANTY; without even the implied warranty of
 | |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | |
| General Public License for more details.
 | |
| 
 | |
| You should have received a copy of the GNU General Public License
 | |
| along with GNU Classpath; see the file COPYING.  If not, write to the
 | |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | |
| 02110-1301 USA.
 | |
| 
 | |
| Linking this library statically or dynamically with other modules is
 | |
| making a combined work based on this library.  Thus, the terms and
 | |
| conditions of the GNU General Public License cover the whole
 | |
| combination.
 | |
| 
 | |
| As a special exception, the copyright holders of this library give you
 | |
| permission to link this library with independent modules to produce an
 | |
| executable, regardless of the license terms of these independent
 | |
| modules, and to copy and distribute the resulting executable under
 | |
| terms of your choice, provided that you also meet, for each linked
 | |
| independent module, the terms and conditions of the license of that
 | |
| module.  An independent module is a module which is not derived from
 | |
| or based on this library.  If you modify this library, you may extend
 | |
| this exception to your version of the library, but you are not
 | |
| obligated to do so.  If you do not wish to do so, delete this
 | |
| exception statement from your version. */
 | |
| 
 | |
| 
 | |
| package javax.swing.text;
 | |
| 
 | |
| import java.awt.Color;
 | |
| import java.awt.Component;
 | |
| import java.awt.Font;
 | |
| import java.awt.FontMetrics;
 | |
| import java.awt.Graphics;
 | |
| import java.awt.Rectangle;
 | |
| import java.awt.Shape;
 | |
| 
 | |
| import javax.swing.SwingUtilities;
 | |
| import javax.swing.event.DocumentEvent;
 | |
| import javax.swing.event.DocumentEvent.ElementChange;
 | |
| 
 | |
| public class PlainView extends View implements TabExpander
 | |
| {
 | |
|   Color selectedColor;
 | |
|   Color unselectedColor;
 | |
| 
 | |
|   /**
 | |
|    * The color that is used to draw disabled text fields.
 | |
|    */
 | |
|   Color disabledColor;
 | |
| 
 | |
|   /**
 | |
|    * While painting this is the textcomponent's current start index
 | |
|    * of the selection.
 | |
|    */
 | |
|   int selectionStart;
 | |
| 
 | |
|   /**
 | |
|    * While painting this is the textcomponent's current end index
 | |
|    * of the selection.
 | |
|    */
 | |
|   int selectionEnd;
 | |
| 
 | |
|   Font font;
 | |
| 
 | |
|   /** The length of the longest line in the Document **/
 | |
|   float maxLineLength = -1;
 | |
| 
 | |
|   /** The longest line in the Document **/
 | |
|   Element longestLine = null;
 | |
| 
 | |
|   protected FontMetrics metrics;
 | |
| 
 | |
|   /**
 | |
|    * The instance returned by {@link #getLineBuffer()}.
 | |
|    */
 | |
|   private transient Segment lineBuffer;
 | |
| 
 | |
|   /**
 | |
|    * The base offset for tab calculations.
 | |
|    */
 | |
|   private int tabBase;
 | |
| 
 | |
|   /**
 | |
|    * The tab size.
 | |
|    */
 | |
|   private int tabSize;
 | |
| 
 | |
|   public PlainView(Element elem)
 | |
|   {
 | |
|     super(elem);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @since 1.4
 | |
|    */
 | |
|   protected void updateMetrics()
 | |
|   {
 | |
|     Component component = getContainer();
 | |
|     Font font = component.getFont();
 | |
| 
 | |
|     if (this.font != font)
 | |
|       {
 | |
|         this.font = font;
 | |
|         metrics = component.getFontMetrics(font);
 | |
|         tabSize = getTabSize() * metrics.charWidth('m');
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * @since 1.4
 | |
|    */
 | |
|   protected Rectangle lineToRect(Shape a, int line)
 | |
|   {
 | |
|     // Ensure metrics are up-to-date.
 | |
|     updateMetrics();
 | |
| 
 | |
|     Rectangle rect = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
 | |
|     int fontHeight = metrics.getHeight();
 | |
|     return new Rectangle(rect.x, rect.y + (line * fontHeight),
 | |
|                          rect.width, fontHeight);
 | |
|   }
 | |
| 
 | |
|   public Shape modelToView(int position, Shape a, Position.Bias b)
 | |
|     throws BadLocationException
 | |
|   {
 | |
|     // Ensure metrics are up-to-date.
 | |
|     updateMetrics();
 | |
| 
 | |
|     Document document = getDocument();
 | |
| 
 | |
|     // Get rectangle of the line containing position.
 | |
|     int lineIndex = getElement().getElementIndex(position);
 | |
|     Rectangle rect = lineToRect(a, lineIndex);
 | |
|     tabBase = rect.x;
 | |
| 
 | |
|     // Get the rectangle for position.
 | |
|     Element line = getElement().getElement(lineIndex);
 | |
|     int lineStart = line.getStartOffset();
 | |
|     Segment segment = getLineBuffer();
 | |
|     document.getText(lineStart, position - lineStart, segment);
 | |
|     int xoffset = Utilities.getTabbedTextWidth(segment, metrics, tabBase,
 | |
|                                                this, lineStart);
 | |
| 
 | |
|     // Calc the real rectangle.
 | |
|     rect.x += xoffset;
 | |
|     rect.width = 1;
 | |
|     rect.height = metrics.getHeight();
 | |
| 
 | |
|     return rect;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Draws a line of text. The X and Y coordinates specify the start of
 | |
|    * the <em>baseline</em> of the line.
 | |
|    *
 | |
|    * @param lineIndex the index of the line
 | |
|    * @param g the graphics to use for drawing the text
 | |
|    * @param x the X coordinate of the baseline
 | |
|    * @param y the Y coordinate of the baseline
 | |
|    */
 | |
|   protected void drawLine(int lineIndex, Graphics g, int x, int y)
 | |
|   {
 | |
|     try
 | |
|       {
 | |
|         Element line = getElement().getElement(lineIndex);
 | |
|         int startOffset = line.getStartOffset();
 | |
|         int endOffset = line.getEndOffset() - 1;
 | |
| 
 | |
|         if (selectionStart <= startOffset)
 | |
|           // Selection starts before the line ...
 | |
|           if (selectionEnd <= startOffset)
 | |
|             {
 | |
|               // end ends before the line: Draw completely unselected text.
 | |
|               drawUnselectedText(g, x, y, startOffset, endOffset);
 | |
|             }
 | |
|           else if (selectionEnd <= endOffset)
 | |
|             {
 | |
|               // and ends within the line: First part is selected,
 | |
|               // second is not.
 | |
|               x = drawSelectedText(g, x, y, startOffset, selectionEnd);
 | |
|               drawUnselectedText(g, x, y, selectionEnd, endOffset);
 | |
|             }
 | |
|           else
 | |
|             // and ends behind the line: Draw completely selected text.
 | |
|             drawSelectedText(g, x, y, startOffset, endOffset);
 | |
|         else if (selectionStart < endOffset)
 | |
|           // Selection starts within the line ..
 | |
|           if (selectionEnd < endOffset)
 | |
|             {
 | |
|               // and ends within it: First part unselected, second part
 | |
|               // selected, third part unselected.
 | |
|               x = drawUnselectedText(g, x, y, startOffset, selectionStart);
 | |
|               x = drawSelectedText(g, x, y, selectionStart, selectionEnd);
 | |
|               drawUnselectedText(g, x, y, selectionEnd, endOffset);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               // and ends behind the line: First part unselected, second
 | |
|               // part selected.
 | |
|               x = drawUnselectedText(g, x, y, startOffset, selectionStart);
 | |
|               drawSelectedText(g, x, y, selectionStart, endOffset);
 | |
|             }
 | |
|         else
 | |
|           // Selection is behind this line: Draw completely unselected text.
 | |
|           drawUnselectedText(g, x, y, startOffset, endOffset);
 | |
|       }
 | |
|     catch (BadLocationException e)
 | |
|     {
 | |
|       AssertionError ae = new AssertionError("Unexpected bad location");
 | |
|       ae.initCause(e);
 | |
|       throw ae;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
 | |
|     throws BadLocationException
 | |
|   {
 | |
|     g.setColor(selectedColor);
 | |
|     Segment segment = getLineBuffer();
 | |
|     getDocument().getText(p0, p1 - p0, segment);
 | |
|     return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Draws a chunk of unselected text.
 | |
|    *
 | |
|    * @param g the graphics to use for drawing the text
 | |
|    * @param x the X coordinate of the baseline
 | |
|    * @param y the Y coordinate of the baseline
 | |
|    * @param p0 the start position in the text model
 | |
|    * @param p1 the end position in the text model
 | |
|    *
 | |
|    * @return the X location of the end of the range
 | |
|    *
 | |
|    * @throws BadLocationException if <code>p0</code> or <code>p1</code> are
 | |
|    *         invalid
 | |
|    */
 | |
|   protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
 | |
|     throws BadLocationException
 | |
|   {
 | |
|     JTextComponent textComponent = (JTextComponent) getContainer();
 | |
|     if (textComponent.isEnabled())
 | |
|       g.setColor(unselectedColor);
 | |
|     else
 | |
|       g.setColor(disabledColor);
 | |
| 
 | |
|     Segment segment = getLineBuffer();
 | |
|     getDocument().getText(p0, p1 - p0, segment);
 | |
|     return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
 | |
|   }
 | |
| 
 | |
|   public void paint(Graphics g, Shape s)
 | |
|   {
 | |
|     // Ensure metrics are up-to-date.
 | |
|     updateMetrics();
 | |
| 
 | |
|     JTextComponent textComponent = (JTextComponent) getContainer();
 | |
| 
 | |
|     selectedColor = textComponent.getSelectedTextColor();
 | |
|     unselectedColor = textComponent.getForeground();
 | |
|     disabledColor = textComponent.getDisabledTextColor();
 | |
|     selectionStart = textComponent.getSelectionStart();
 | |
|     selectionEnd = textComponent.getSelectionEnd();
 | |
| 
 | |
|     Rectangle rect = s instanceof Rectangle ? (Rectangle) s : s.getBounds();
 | |
|     tabBase = rect.x;
 | |
| 
 | |
|     // FIXME: Text may be scrolled.
 | |
|     Document document = textComponent.getDocument();
 | |
|     Element root = getElement();
 | |
|     int height = metrics.getHeight();
 | |
| 
 | |
|     // For layered highlighters we need to paint the layered highlights
 | |
|     // before painting any text.
 | |
|     LayeredHighlighter hl = null;
 | |
|     Highlighter h = textComponent.getHighlighter();
 | |
|     if (h instanceof LayeredHighlighter)
 | |
|       hl = (LayeredHighlighter) h;
 | |
| 
 | |
|     int count = root.getElementCount();
 | |
| 
 | |
|     // Determine first and last line inside the clip.
 | |
|     Rectangle clip = g.getClipBounds();
 | |
|     SwingUtilities.computeIntersection(rect.x, rect.y, rect.width, rect.height,
 | |
|                                        clip);
 | |
|     int line0 = (clip.y - rect.y) / height;
 | |
|     line0 = Math.max(0, Math.min(line0, count - 1));
 | |
|     int line1 = (clip.y + clip.height - rect.y) / height;
 | |
|     line1 = Math.max(0, Math.min(line1, count - 1));
 | |
|     int y = rect.y + metrics.getAscent() + height * line0;
 | |
|     for (int i = line0; i <= line1; i++)
 | |
|       {
 | |
|         if (hl != null)
 | |
|           {
 | |
|             Element lineEl = root.getElement(i);
 | |
|             // Exclude the trailing newline from beeing highlighted.
 | |
|             if (i == count)
 | |
|               hl.paintLayeredHighlights(g, lineEl.getStartOffset(),
 | |
|                                         lineEl.getEndOffset(), s, textComponent,
 | |
|                                         this);
 | |
|             else
 | |
|               hl.paintLayeredHighlights(g, lineEl.getStartOffset(),
 | |
|                                         lineEl.getEndOffset() - 1, s,
 | |
|                                         textComponent, this);
 | |
|           }
 | |
|         drawLine(i, g, rect.x, y);
 | |
|         y += height;
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the tab size of a tab.  Checks the Document's
 | |
|    * properties for PlainDocument.tabSizeAttribute and returns it if it is
 | |
|    * defined, otherwise returns 8.
 | |
|    *
 | |
|    * @return the tab size.
 | |
|    */
 | |
|   protected int getTabSize()
 | |
|   {
 | |
|     Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
 | |
|     if (tabSize == null)
 | |
|       return 8;
 | |
|     return ((Integer)tabSize).intValue();
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the next tab stop position after a given reference position.
 | |
|    *
 | |
|    * This implementation ignores the <code>tabStop</code> argument.
 | |
|    *
 | |
|    * @param x the current x position in pixels
 | |
|    * @param tabStop the position within the text stream that the tab occured at
 | |
|    */
 | |
|   public float nextTabStop(float x, int tabStop)
 | |
|   {
 | |
|     float next = x;
 | |
|     if (tabSize != 0)
 | |
|       {
 | |
|         int numTabs = (((int) x) - tabBase) / tabSize;
 | |
|         next = tabBase + (numTabs + 1) * tabSize;
 | |
|       }
 | |
|     return next;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Returns the length of the longest line, used for getting the span
 | |
|    * @return the length of the longest line
 | |
|    */
 | |
|   float determineMaxLineLength()
 | |
|   {
 | |
|     // if the longest line is cached, return the cached value
 | |
|     if (maxLineLength != -1)
 | |
|       return maxLineLength;
 | |
| 
 | |
|     // otherwise we have to go through all the lines and find it
 | |
|     Element el = getElement();
 | |
|     Segment seg = getLineBuffer();
 | |
|     float span = 0;
 | |
|     for (int i = 0; i < el.getElementCount(); i++)
 | |
|       {
 | |
|         Element child = el.getElement(i);
 | |
|         int start = child.getStartOffset();
 | |
|         int end = child.getEndOffset() - 1;
 | |
|         try
 | |
|           {
 | |
|             el.getDocument().getText(start, end - start, seg);
 | |
|           }
 | |
|         catch (BadLocationException ex)
 | |
|           {
 | |
|             AssertionError ae = new AssertionError("Unexpected bad location");
 | |
|             ae.initCause(ex);
 | |
|             throw ae;
 | |
|           }
 | |
| 
 | |
|         if (seg == null || seg.array == null || seg.count == 0)
 | |
|           continue;
 | |
| 
 | |
|         int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
 | |
|         if (width > span)
 | |
|           {
 | |
|             longestLine = child;
 | |
|             span = width;
 | |
|           }
 | |
|       }
 | |
|     maxLineLength = span;
 | |
|     return maxLineLength;
 | |
|   }
 | |
| 
 | |
|   public float getPreferredSpan(int axis)
 | |
|   {
 | |
|     if (axis != X_AXIS && axis != Y_AXIS)
 | |
|       throw new IllegalArgumentException();
 | |
| 
 | |
|     // make sure we have the metrics
 | |
|     updateMetrics();
 | |
| 
 | |
|     Element el = getElement();
 | |
|     float span;
 | |
| 
 | |
|     switch (axis)
 | |
|       {
 | |
|       case X_AXIS:
 | |
|         span = determineMaxLineLength();
 | |
|         break;
 | |
|       case Y_AXIS:
 | |
|       default:
 | |
|         span = metrics.getHeight() * el.getElementCount();
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|     return span;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Maps coordinates from the <code>View</code>'s space into a position
 | |
|    * in the document model.
 | |
|    *
 | |
|    * @param x the x coordinate in the view space
 | |
|    * @param y the y coordinate in the view space
 | |
|    * @param a the allocation of this <code>View</code>
 | |
|    * @param b the bias to use
 | |
|    *
 | |
|    * @return the position in the document that corresponds to the screen
 | |
|    *         coordinates <code>x, y</code>
 | |
|    */
 | |
|   public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
 | |
|   {
 | |
|     Rectangle rec = a instanceof Rectangle ? (Rectangle) a : a.getBounds();
 | |
|     tabBase = rec.x;
 | |
| 
 | |
|     int pos;
 | |
|     if ((int) y < rec.y)
 | |
|       // Above our area vertically. Return start offset.
 | |
|       pos = getStartOffset();
 | |
|     else if ((int) y > rec.y + rec.height)
 | |
|       // Below our area vertically. Return end offset.
 | |
|       pos = getEndOffset() - 1;
 | |
|     else
 | |
|       {
 | |
|         // Inside the allocation vertically. Determine line and X offset.
 | |
|         Document doc = getDocument();
 | |
|         Element root = doc.getDefaultRootElement();
 | |
|         int line = Math.abs(((int) y - rec.y) / metrics.getHeight());
 | |
|         if (line >= root.getElementCount())
 | |
|           pos = getEndOffset() - 1;
 | |
|         else
 | |
|           {
 | |
|             Element lineEl = root.getElement(line);
 | |
|             if (x < rec.x)
 | |
|               // To the left of the allocation area.
 | |
|               pos = lineEl.getStartOffset();
 | |
|             else if (x > rec.x + rec.width)
 | |
|               // To the right of the allocation area.
 | |
|               pos = lineEl.getEndOffset() - 1;
 | |
|             else
 | |
|               {
 | |
|                 try
 | |
|                   {
 | |
|                     int p0 = lineEl.getStartOffset();
 | |
|                     int p1 = lineEl.getEndOffset();
 | |
|                     Segment s = new Segment();
 | |
|                     doc.getText(p0, p1 - p0, s);
 | |
|                     tabBase = rec.x;
 | |
|                     pos = p0 + Utilities.getTabbedTextOffset(s, metrics,
 | |
|                                                              tabBase, (int) x,
 | |
|                                                              this, p0);
 | |
|                   }
 | |
|                 catch (BadLocationException ex)
 | |
|                   {
 | |
|                     // Should not happen.
 | |
|                     pos = -1;
 | |
|                   }
 | |
|               }
 | |
| 
 | |
|           }
 | |
|       }
 | |
|     // Bias is always forward.
 | |
|     b[0] = Position.Bias.Forward;
 | |
|     return pos;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Since insertUpdate and removeUpdate each deal with children
 | |
|    * Elements being both added and removed, they both have to perform
 | |
|    * the same checks.  So they both simply call this method.
 | |
|    * @param changes the DocumentEvent for the changes to the Document.
 | |
|    * @param a the allocation of the View.
 | |
|    * @param f the ViewFactory to use for rebuilding.
 | |
|    */
 | |
|   protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
 | |
|   {
 | |
|     // This happens during initialization.
 | |
|     if (metrics == null)
 | |
|       {
 | |
|         updateMetrics();
 | |
|         preferenceChanged(null, true, true);
 | |
|         return;
 | |
|       }
 | |
| 
 | |
|     Element element = getElement();
 | |
| 
 | |
|     // Find longest line if it hasn't been initialized yet.
 | |
|     if (longestLine == null)
 | |
|       findLongestLine(0, element.getElementCount() - 1);
 | |
| 
 | |
|     ElementChange change = changes.getChange(element);
 | |
|     if (changes.getType() == DocumentEvent.EventType.INSERT)
 | |
|       {
 | |
|         // Handles character/line insertion.
 | |
| 
 | |
|         // Determine if lines have been added. In this case we repaint
 | |
|         // differently.
 | |
|         boolean linesAdded = true;
 | |
|         if (change == null)
 | |
|           linesAdded = false;
 | |
| 
 | |
|         // Determine the start line.
 | |
|         int start;
 | |
|         if (linesAdded)
 | |
|           start = change.getIndex();
 | |
|         else
 | |
|           start = element.getElementIndex(changes.getOffset());
 | |
| 
 | |
|         // Determine the length of the updated region.
 | |
|         int length = 0;
 | |
|         if (linesAdded)
 | |
|           length = change.getChildrenAdded().length - 1;
 | |
| 
 | |
|         // Update the longest line and length.
 | |
|         int oldMaxLength = (int) maxLineLength;
 | |
|         if (longestLine.getEndOffset() < changes.getOffset()
 | |
|             || longestLine.getStartOffset() > changes.getOffset()
 | |
|                                              + changes.getLength())
 | |
|           {
 | |
|             findLongestLine(start, start + length);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             findLongestLine(0, element.getElementCount() - 1);
 | |
|           }
 | |
| 
 | |
|         // Trigger a preference change so that the layout gets updated
 | |
|         // correctly.
 | |
|         preferenceChanged(null, maxLineLength != oldMaxLength, linesAdded);
 | |
| 
 | |
|         // Damage the updated line range.
 | |
|         int endLine = start;
 | |
|         if (linesAdded)
 | |
|           endLine = element.getElementCount() - 1;
 | |
|         damageLineRange(start, endLine, a, getContainer());
 | |
| 
 | |
|       }
 | |
|     else
 | |
|       {
 | |
|         // Handles character/lines removals.
 | |
| 
 | |
|         // Update the longest line and length and trigger preference changed.
 | |
|         int oldMaxLength = (int) maxLineLength;
 | |
|         if (change != null)
 | |
|           {
 | |
|             // Line(s) have been removed.
 | |
|             findLongestLine(0, element.getElementCount() - 1);
 | |
|             preferenceChanged(null, maxLineLength != oldMaxLength, true);
 | |
|           }
 | |
|         else
 | |
|           {
 | |
|             // No line has been removed.
 | |
|             int lineNo = getElement().getElementIndex(changes.getOffset());
 | |
|             Element line = getElement().getElement(lineNo);
 | |
|             if (longestLine == line)
 | |
|               {
 | |
|                 findLongestLine(0, element.getElementCount() - 1);
 | |
|                 preferenceChanged(null, maxLineLength != oldMaxLength, false);
 | |
|             }
 | |
|             damageLineRange(lineNo, lineNo, a, getContainer());
 | |
|         }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method is called when something is inserted into the Document
 | |
|    * that this View is displaying.
 | |
|    *
 | |
|    * @param changes the DocumentEvent for the changes.
 | |
|    * @param a the allocation of the View
 | |
|    * @param f the ViewFactory used to rebuild
 | |
|    */
 | |
|   public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
 | |
|   {
 | |
|     updateDamage(changes, a, f);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method is called when something is removed from the Document
 | |
|    * that this View is displaying.
 | |
|    *
 | |
|    * @param changes the DocumentEvent for the changes.
 | |
|    * @param a the allocation of the View
 | |
|    * @param f the ViewFactory used to rebuild
 | |
|    */
 | |
|   public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
 | |
|   {
 | |
|     updateDamage(changes, a, f);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * This method is called when attributes were changed in the
 | |
|    * Document in a location that this view is responsible for.
 | |
|    */
 | |
|   public void changedUpdate (DocumentEvent changes, Shape a, ViewFactory f)
 | |
|   {
 | |
|     updateDamage(changes, a, f);
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Repaint the given line range.  This is called from insertUpdate,
 | |
|    * changedUpdate, and removeUpdate when no new lines were added
 | |
|    * and no lines were removed, to repaint the line that was
 | |
|    * modified.
 | |
|    *
 | |
|    * @param line0 the start of the range
 | |
|    * @param line1 the end of the range
 | |
|    * @param a the rendering region of the host
 | |
|    * @param host the Component that uses this View (used to call repaint
 | |
|    * on that Component)
 | |
|    *
 | |
|    * @since 1.4
 | |
|    */
 | |
|   protected void damageLineRange (int line0, int line1, Shape a, Component host)
 | |
|   {
 | |
|     if (a == null)
 | |
|       return;
 | |
| 
 | |
|     Rectangle rec0 = lineToRect(a, line0);
 | |
|     Rectangle rec1 = lineToRect(a, line1);
 | |
| 
 | |
|     if (rec0 == null || rec1 == null)
 | |
|       // something went wrong, repaint the entire host to be safe
 | |
|       host.repaint();
 | |
|     else
 | |
|       {
 | |
|         Rectangle repaintRec = SwingUtilities.computeUnion(rec0.x, rec0.y,
 | |
|                                                            rec0.width,
 | |
|                                                            rec0.height, rec1);
 | |
|         host.repaint(repaintRec.x, repaintRec.y, repaintRec.width,
 | |
|                      repaintRec.height);
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Provides a {@link Segment} object, that can be used to fetch text from
 | |
|    * the document.
 | |
|    *
 | |
|    * @returna {@link Segment} object, that can be used to fetch text from
 | |
|    *          the document
 | |
|    */
 | |
|   protected final Segment getLineBuffer()
 | |
|   {
 | |
|     if (lineBuffer == null)
 | |
|       lineBuffer = new Segment();
 | |
|     return lineBuffer;
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Finds and updates the longest line in the view inside an interval of
 | |
|    * lines.
 | |
|    *
 | |
|    * @param start the start of the search interval
 | |
|    * @param end the end of the search interval
 | |
|    */
 | |
|   private void findLongestLine(int start, int end)
 | |
|   {
 | |
|     for (int i = start; i <= end; i++)
 | |
|       {
 | |
|         int w = getLineLength(i);
 | |
|         if (w > maxLineLength)
 | |
|           {
 | |
|             maxLineLength = w;
 | |
|             longestLine = getElement().getElement(i);
 | |
|           }
 | |
|       }
 | |
|   }
 | |
| 
 | |
|   /**
 | |
|    * Determines the length of the specified line.
 | |
|    *
 | |
|    * @param line the number of the line
 | |
|    *
 | |
|    * @return the length of the line in pixels
 | |
|    */
 | |
|   private int getLineLength(int line)
 | |
|   {
 | |
|     Element lineEl = getElement().getElement(line);
 | |
|     Segment buffer = getLineBuffer();
 | |
|     try
 | |
|       {
 | |
|         Document doc = getDocument();
 | |
|         doc.getText(lineEl.getStartOffset(),
 | |
|                     lineEl.getEndOffset() - lineEl.getStartOffset() - 1,
 | |
|                     buffer);
 | |
|       }
 | |
|     catch (BadLocationException ex)
 | |
|       {
 | |
|         AssertionError err = new AssertionError("Unexpected bad location");
 | |
|         err.initCause(ex);
 | |
|         throw err;
 | |
|       }
 | |
| 
 | |
|     return Utilities.getTabbedTextWidth(buffer, metrics, tabBase, this,
 | |
|                                         lineEl.getStartOffset());
 | |
|   }
 | |
| }
 |