Remove old autovect-branch by moving to "dead" directory.
[official-gcc.git] / old-autovect-branch / libjava / classpath / javax / swing / text / PlainView.java
blob9f5ee8ad3c8e18aaf326ebdbd3baf43621d5c77e
1 /* PlainView.java --
2 Copyright (C) 2004, 2005 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Color;
42 import java.awt.Component;
43 import java.awt.Font;
44 import java.awt.FontMetrics;
45 import java.awt.Graphics;
46 import java.awt.Rectangle;
47 import java.awt.Shape;
49 import javax.swing.SwingConstants;
50 import javax.swing.event.DocumentEvent;
51 import javax.swing.event.DocumentEvent.ElementChange;
53 public class PlainView extends View implements TabExpander
55 Color selectedColor;
56 Color unselectedColor;
58 /**
59 * The color that is used to draw disabled text fields.
61 Color disabledColor;
63 Font font;
65 /** The length of the longest line in the Document **/
66 float maxLineLength = -1;
68 /** The longest line in the Document **/
69 Element longestLine = null;
71 protected FontMetrics metrics;
73 /**
74 * The instance returned by {@link #getLineBuffer()}.
76 private transient Segment lineBuffer;
78 public PlainView(Element elem)
80 super(elem);
83 /**
84 * @since 1.4
86 protected void updateMetrics()
88 Component component = getContainer();
89 Font font = component.getFont();
91 if (this.font != font)
93 this.font = font;
94 metrics = component.getFontMetrics(font);
98 /**
99 * @since 1.4
101 protected Rectangle lineToRect(Shape a, int line)
103 // Ensure metrics are up-to-date.
104 updateMetrics();
106 Rectangle rect = a.getBounds();
107 int fontHeight = metrics.getHeight();
108 return new Rectangle(rect.x, rect.y + (line * fontHeight),
109 rect.width, fontHeight);
112 public Shape modelToView(int position, Shape a, Position.Bias b)
113 throws BadLocationException
115 // Ensure metrics are up-to-date.
116 updateMetrics();
118 Document document = getDocument();
120 // Get rectangle of the line containing position.
121 int lineIndex = getElement().getElementIndex(position);
122 Rectangle rect = lineToRect(a, lineIndex);
124 // Get the rectangle for position.
125 Element line = getElement().getElement(lineIndex);
126 int lineStart = line.getStartOffset();
127 Segment segment = getLineBuffer();
128 document.getText(lineStart, position - lineStart, segment);
129 int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x,
130 this, lineStart);
132 // Calc the real rectangle.
133 rect.x += xoffset;
134 rect.width = 1;
135 rect.height = metrics.getHeight();
137 return rect;
140 protected void drawLine(int lineIndex, Graphics g, int x, int y)
144 metrics = g.getFontMetrics();
145 // FIXME: Selected text are not drawn yet.
146 Element line = getElement().getElement(lineIndex);
147 drawUnselectedText(g, x, y, line.getStartOffset(), line.getEndOffset());
148 //drawSelectedText(g, , , , );
150 catch (BadLocationException e)
152 AssertionError ae = new AssertionError("Unexpected bad location");
153 ae.initCause(e);
154 throw ae;
158 protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
159 throws BadLocationException
161 g.setColor(selectedColor);
162 Segment segment = getLineBuffer();
163 getDocument().getText(p0, p1 - p0, segment);
164 return Utilities.drawTabbedText(segment, x, y, g, this, 0);
167 protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
168 throws BadLocationException
170 JTextComponent textComponent = (JTextComponent) getContainer();
171 if (textComponent.isEnabled())
172 g.setColor(unselectedColor);
173 else
174 g.setColor(disabledColor);
176 Segment segment = getLineBuffer();
177 getDocument().getText(p0, p1 - p0, segment);
178 return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset);
181 public void paint(Graphics g, Shape s)
183 // Ensure metrics are up-to-date.
184 updateMetrics();
186 JTextComponent textComponent = (JTextComponent) getContainer();
188 g.setFont(textComponent.getFont());
189 selectedColor = textComponent.getSelectedTextColor();
190 unselectedColor = textComponent.getForeground();
191 disabledColor = textComponent.getDisabledTextColor();
193 Rectangle rect = s.getBounds();
195 // FIXME: Text may be scrolled.
196 Document document = textComponent.getDocument();
197 Element root = document.getDefaultRootElement();
198 int y = rect.y;
200 for (int i = 0; i < root.getElementCount(); i++)
202 drawLine(i, g, rect.x, y);
203 y += metrics.getHeight();
208 * Returns the tab size of a tab. Checks the Document's
209 * properties for PlainDocument.tabSizeAttribute and returns it if it is
210 * defined, otherwise returns 8.
212 * @return the tab size.
214 protected int getTabSize()
216 Object tabSize = getDocument().getProperty(PlainDocument.tabSizeAttribute);
217 if (tabSize == null)
218 return 8;
219 return ((Integer)tabSize).intValue();
223 * Returns the next tab stop position after a given reference position.
225 * This implementation ignores the <code>tabStop</code> argument.
227 * @param x the current x position in pixels
228 * @param tabStop the position within the text stream that the tab occured at
230 public float nextTabStop(float x, int tabStop)
232 float tabSizePixels = getTabSize() * metrics.charWidth('m');
233 return (float) (Math.floor(x / tabSizePixels) + 1) * tabSizePixels;
237 * Returns the length of the longest line, used for getting the span
238 * @return the length of the longest line
240 float determineMaxLineLength()
242 // if the longest line is cached, return the cached value
243 if (maxLineLength != -1)
244 return maxLineLength;
246 // otherwise we have to go through all the lines and find it
247 Element el = getElement();
248 Segment seg = getLineBuffer();
249 float span = 0;
250 for (int i = 0; i < el.getElementCount(); i++)
252 Element child = el.getElement(i);
253 int start = child.getStartOffset();
254 int end = child.getEndOffset();
257 el.getDocument().getText(start, end - start, seg);
259 catch (BadLocationException ex)
261 AssertionError ae = new AssertionError("Unexpected bad location");
262 ae.initCause(ex);
263 throw ae;
266 if (seg == null || seg.array == null || seg.count == 0)
267 continue;
269 int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
270 if (width > span)
272 longestLine = child;
273 span = width;
276 maxLineLength = span;
277 return maxLineLength;
280 public float getPreferredSpan(int axis)
282 if (axis != X_AXIS && axis != Y_AXIS)
283 throw new IllegalArgumentException();
285 // make sure we have the metrics
286 updateMetrics();
288 float span = 0;
289 Element el = getElement();
291 switch (axis)
293 case X_AXIS:
294 span = determineMaxLineLength();
295 case Y_AXIS:
296 default:
297 span = metrics.getHeight() * el.getElementCount();
298 break;
300 return span;
304 * Maps coordinates from the <code>View</code>'s space into a position
305 * in the document model.
307 * @param x the x coordinate in the view space
308 * @param y the y coordinate in the view space
309 * @param a the allocation of this <code>View</code>
310 * @param b the bias to use
312 * @return the position in the document that corresponds to the screen
313 * coordinates <code>x, y</code>
315 public int viewToModel(float x, float y, Shape a, Position.Bias[] b)
317 Rectangle rec = a.getBounds();
318 Document doc = getDocument();
319 Element root = doc.getDefaultRootElement();
321 // PlainView doesn't support line-wrapping so we can find out which
322 // Element was clicked on just by the y-position
323 int lineClicked = (int) (y - rec.y) / metrics.getHeight();
324 if (lineClicked >= root.getElementCount())
325 return getEndOffset() - 1;
327 Element line = root.getElement(lineClicked);
328 Segment s = getLineBuffer();
329 int start = line.getStartOffset();
330 // We don't want the \n at the end of the line.
331 int end = line.getEndOffset() - 1;
334 doc.getText(start, end - start, s);
336 catch (BadLocationException ble)
338 AssertionError ae = new AssertionError("Unexpected bad location");
339 ae.initCause(ble);
340 throw ae;
343 int pos = Utilities.getTabbedTextOffset(s, metrics, rec.x, (int)x, this, start);
344 return Math.max (0, pos);
348 * Since insertUpdate and removeUpdate each deal with children
349 * Elements being both added and removed, they both have to perform
350 * the same checks. So they both simply call this method.
351 * @param changes the DocumentEvent for the changes to the Document.
352 * @param a the allocation of the View.
353 * @param f the ViewFactory to use for rebuilding.
355 protected void updateDamage(DocumentEvent changes, Shape a, ViewFactory f)
357 Element el = getElement();
358 ElementChange ec = changes.getChange(el);
360 // If ec is null then no lines were added or removed, just
361 // repaint the changed line
362 if (ec == null)
364 int line = getElement().getElementIndex(changes.getOffset());
365 damageLineRange(line, line, a, getContainer());
366 return;
369 Element[] removed = ec.getChildrenRemoved();
370 Element[] newElements = ec.getChildrenAdded();
372 // If no Elements were added or removed, we just want to repaint
373 // the area containing the line that was modified
374 if (removed == null && newElements == null)
376 int line = getElement().getElementIndex(changes.getOffset());
377 damageLineRange(line, line, a, getContainer());
378 return;
381 // Check to see if we removed the longest line, if so we have to
382 // search through all lines and find the longest one again
383 if (removed != null)
385 for (int i = 0; i < removed.length; i++)
386 if (removed[i].equals(longestLine))
388 // reset maxLineLength and search through all lines for longest one
389 maxLineLength = -1;
390 determineMaxLineLength();
391 ((JTextComponent)getContainer()).repaint();
392 return;
396 // If we've reached here, that means we haven't removed the longest line
397 if (newElements == null)
399 // No lines were added, just repaint the container and exit
400 ((JTextComponent)getContainer()).repaint();
401 return;
404 // Make sure we have the metrics
405 updateMetrics();
407 // If we've reached here, that means we haven't removed the longest line
408 // and we have added at least one line, so we have to check if added lines
409 // are longer than the previous longest line
410 Segment seg = getLineBuffer();
411 float longestNewLength = 0;
412 Element longestNewLine = null;
414 // Loop through the added lines to check their length
415 for (int i = 0; i < newElements.length; i++)
417 Element child = newElements[i];
418 int start = child.getStartOffset();
419 int end = child.getEndOffset();
422 el.getDocument().getText(start, end - start, seg);
424 catch (BadLocationException ex)
426 AssertionError ae = new AssertionError("Unexpected bad location");
427 ae.initCause(ex);
428 throw ae;
431 if (seg == null || seg.array == null || seg.count == 0)
432 continue;
434 int width = metrics.charsWidth(seg.array, seg.offset, seg.count);
435 if (width > longestNewLength)
437 longestNewLine = child;
438 longestNewLength = width;
442 // Check if the longest of the new lines is longer than our previous
443 // longest line, and if so update our values
444 if (longestNewLength > maxLineLength)
446 maxLineLength = longestNewLength;
447 longestLine = longestNewLine;
449 // Repaint the container
450 ((JTextComponent)getContainer()).repaint();
454 * This method is called when something is inserted into the Document
455 * that this View is displaying.
457 * @param changes the DocumentEvent for the changes.
458 * @param a the allocation of the View
459 * @param f the ViewFactory used to rebuild
461 public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f)
463 updateDamage(changes, a, f);
467 * This method is called when something is removed from the Document
468 * that this View is displaying.
470 * @param changes the DocumentEvent for the changes.
471 * @param a the allocation of the View
472 * @param f the ViewFactory used to rebuild
474 public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f)
476 updateDamage(changes, a, f);
480 * This method is called when attributes were changed in the
481 * Document in a location that this view is responsible for.
483 public void changedUpdate (DocumentEvent changes, Shape a, ViewFactory f)
485 updateDamage(changes, a, f);
489 * Repaint the given line range. This is called from insertUpdate,
490 * changedUpdate, and removeUpdate when no new lines were added
491 * and no lines were removed, to repaint the line that was
492 * modified.
494 * @param line0 the start of the range
495 * @param line1 the end of the range
496 * @param a the rendering region of the host
497 * @param host the Component that uses this View (used to call repaint
498 * on that Component)
500 * @since 1.4
502 protected void damageLineRange (int line0, int line1, Shape a, Component host)
504 if (a == null)
505 return;
507 Rectangle rec0 = lineToRect(a, line0);
508 Rectangle rec1 = lineToRect(a, line1);
510 if (rec0 == null || rec1 == null)
511 // something went wrong, repaint the entire host to be safe
512 host.repaint();
513 else
515 Rectangle repaintRec = rec0.union(rec1);
516 host.repaint();
521 * Provides a {@link Segment} object, that can be used to fetch text from
522 * the document.
524 * @returna {@link Segment} object, that can be used to fetch text from
525 * the document
527 protected Segment getLineBuffer()
529 if (lineBuffer == null)
530 lineBuffer = new Segment();
531 return lineBuffer;
535 * Returns the document position that is (visually) nearest to the given
536 * document position <code>pos</code> in the given direction <code>d</code>.
538 * @param c the text component
539 * @param pos the document position
540 * @param b the bias for <code>pos</code>
541 * @param d the direction, must be either {@link SwingConstants#NORTH},
542 * {@link SwingConstants#SOUTH}, {@link SwingConstants#WEST} or
543 * {@link SwingConstants#EAST}
544 * @param biasRet an array of {@link Position.Bias} that can hold at least
545 * one element, which is filled with the bias of the return position
546 * on method exit
548 * @return the document position that is (visually) nearest to the given
549 * document position <code>pos</code> in the given direction
550 * <code>d</code>
552 * @throws BadLocationException if <code>pos</code> is not a valid offset in
553 * the document model
555 public int getNextVisualPositionFrom(JTextComponent c, int pos,
556 Position.Bias b, int d,
557 Position.Bias[] biasRet)
558 throws BadLocationException
560 // TODO: Implement this properly.
561 throw new AssertionError("Not implemented yet.");