45 |
import java.awt.Rectangle; |
import java.awt.Rectangle; |
46 |
import java.awt.Shape; |
import java.awt.Shape; |
47 |
|
|
48 |
|
import javax.swing.SwingConstants; |
49 |
import javax.swing.event.DocumentEvent; |
import javax.swing.event.DocumentEvent; |
50 |
import javax.swing.text.Position.Bias; |
import javax.swing.text.Position.Bias; |
51 |
|
|
52 |
/** |
/** |
53 |
* @author abalkiss |
* @author Anthony Balkissoon abalkiss at redhat dot com |
54 |
* |
* |
55 |
*/ |
*/ |
56 |
public class WrappedPlainView extends BoxView implements TabExpander |
public class WrappedPlainView extends BoxView implements TabExpander |
73 |
/** A ViewFactory that creates WrappedLines **/ |
/** A ViewFactory that creates WrappedLines **/ |
74 |
ViewFactory viewFactory = new WrappedLineCreator(); |
ViewFactory viewFactory = new WrappedLineCreator(); |
75 |
|
|
76 |
|
/** The start of the selected text **/ |
77 |
|
int selectionStart; |
78 |
|
|
79 |
|
/** The end of the selected text **/ |
80 |
|
int selectionEnd; |
81 |
|
|
82 |
/** |
/** |
83 |
* The instance returned by {@link #getLineBuffer()}. |
* The instance returned by {@link #getLineBuffer()}. |
84 |
*/ |
*/ |
150 |
{ |
{ |
151 |
try |
try |
152 |
{ |
{ |
153 |
drawUnselectedText(g, x, y, p0, p1); |
// We have to draw both selected and unselected text. There are |
154 |
|
// several cases: |
155 |
|
// - entire range is unselected |
156 |
|
// - entire range is selected |
157 |
|
// - start of range is selected, end of range is unselected |
158 |
|
// - start of range is unselected, end of range is selected |
159 |
|
// - middle of range is selected, start and end of range is unselected |
160 |
|
|
161 |
|
// entire range unselected: |
162 |
|
if ((selectionStart == selectionEnd) || |
163 |
|
(p0 > selectionEnd || p1 < selectionStart)) |
164 |
|
drawUnselectedText(g, x, y, p0, p1); |
165 |
|
|
166 |
|
// entire range selected |
167 |
|
else if (p0 >= selectionStart && p1 <= selectionEnd) |
168 |
|
drawSelectedText(g, x, y, p0, p1); |
169 |
|
|
170 |
|
// start of range selected, end of range unselected |
171 |
|
else if (p0 >= selectionStart) |
172 |
|
{ |
173 |
|
x = drawSelectedText(g, x, y, p0, selectionEnd); |
174 |
|
drawUnselectedText(g, x, y, selectionEnd, p1); |
175 |
|
} |
176 |
|
|
177 |
|
// start of range unselected, end of range selected |
178 |
|
else if (selectionStart > p0 && selectionEnd > p1) |
179 |
|
{ |
180 |
|
x = drawUnselectedText(g, x, y, p0, selectionStart); |
181 |
|
drawSelectedText(g, x, y, selectionStart, p1); |
182 |
|
} |
183 |
|
|
184 |
|
// middle of range selected |
185 |
|
else if (selectionStart > p0) |
186 |
|
{ |
187 |
|
x = drawUnselectedText(g, x, y, p0, selectionStart); |
188 |
|
x = drawSelectedText(g, x, y, selectionStart, selectionEnd); |
189 |
|
drawUnselectedText(g, x, y, selectionEnd, p1); |
190 |
|
} |
191 |
} |
} |
192 |
catch (BadLocationException ble) |
catch (BadLocationException ble) |
193 |
{ |
{ |
213 |
g.setColor(selectedColor); |
g.setColor(selectedColor); |
214 |
Segment segment = getLineBuffer(); |
Segment segment = getLineBuffer(); |
215 |
getDocument().getText(p0, p1 - p0, segment); |
getDocument().getText(p0, p1 - p0, segment); |
216 |
return Utilities.drawTabbedText(segment, x, y, g, this, 0); |
return Utilities.drawTabbedText(segment, x, y, g, this, p0); |
217 |
} |
} |
218 |
|
|
219 |
/** |
/** |
228 |
*/ |
*/ |
229 |
protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) |
protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1) |
230 |
throws BadLocationException |
throws BadLocationException |
231 |
{ |
{ |
232 |
JTextComponent textComponent = (JTextComponent) getContainer(); |
JTextComponent textComponent = (JTextComponent) getContainer(); |
233 |
if (textComponent.isEnabled()) |
if (textComponent.isEnabled()) |
234 |
g.setColor(unselectedColor); |
g.setColor(unselectedColor); |
237 |
|
|
238 |
Segment segment = getLineBuffer(); |
Segment segment = getLineBuffer(); |
239 |
getDocument().getText(p0, p1 - p0, segment); |
getDocument().getText(p0, p1 - p0, segment); |
240 |
return Utilities.drawTabbedText(segment, x, y, g, this, segment.offset); |
return Utilities.drawTabbedText(segment, x, y, g, this, p0); |
241 |
} |
} |
242 |
|
|
243 |
/** |
/** |
311 |
} |
} |
312 |
|
|
313 |
/** |
/** |
314 |
|
* Determines the minimum span along the given axis. Implemented to |
315 |
|
* cache the font metrics and then call the super classes method. |
316 |
|
*/ |
317 |
|
public float getMinimumSpan (int axis) |
318 |
|
{ |
319 |
|
updateMetrics(); |
320 |
|
return super.getMinimumSpan(axis); |
321 |
|
} |
322 |
|
|
323 |
|
/** |
324 |
|
* Determines the maximum span along the given axis. Implemented to |
325 |
|
* cache the font metrics and then call the super classes method. |
326 |
|
*/ |
327 |
|
public float getMaximumSpan (int axis) |
328 |
|
{ |
329 |
|
updateMetrics(); |
330 |
|
return super.getMaximumSpan(axis); |
331 |
|
} |
332 |
|
|
333 |
|
/** |
334 |
* Called when something was inserted. Overridden so that |
* Called when something was inserted. Overridden so that |
335 |
* the view factory creates WrappedLine views. |
* the view factory creates WrappedLine views. |
336 |
*/ |
*/ |
383 |
*/ |
*/ |
384 |
public void paint(Graphics g, Shape a) |
public void paint(Graphics g, Shape a) |
385 |
{ |
{ |
386 |
|
JTextComponent comp = (JTextComponent)getContainer(); |
387 |
|
selectionStart = comp.getSelectionStart(); |
388 |
|
selectionEnd = comp.getSelectionEnd(); |
389 |
updateMetrics(); |
updateMetrics(); |
390 |
super.paint(g, a); |
super.paint(g, a); |
391 |
} |
} |
397 |
public void setSize (float width, float height) |
public void setSize (float width, float height) |
398 |
{ |
{ |
399 |
updateMetrics(); |
updateMetrics(); |
400 |
|
if (width != getWidth()) |
401 |
|
preferenceChanged(null, true, true); |
402 |
super.setSize(width, height); |
super.setSize(width, height); |
403 |
} |
} |
404 |
|
|
428 |
unselectedColor = textComponent.getForeground(); |
unselectedColor = textComponent.getForeground(); |
429 |
disabledColor = textComponent.getDisabledTextColor(); |
disabledColor = textComponent.getDisabledTextColor(); |
430 |
|
|
431 |
|
// FIXME: this is a hack, for some reason textComponent.getSelectedColor |
432 |
|
// was returning black, which is not visible against a black background |
433 |
|
selectedColor = Color.WHITE; |
434 |
|
|
435 |
Rectangle rect = s.getBounds(); |
Rectangle rect = s.getBounds(); |
436 |
int lineHeight = metrics.getHeight(); |
int lineHeight = metrics.getHeight(); |
437 |
|
|
457 |
*/ |
*/ |
458 |
int determineNumLines() |
int determineNumLines() |
459 |
{ |
{ |
460 |
|
numLines = 0; |
461 |
int end = getEndOffset(); |
int end = getEndOffset(); |
462 |
if (end == 0) |
if (end == 0) |
463 |
return 0; |
return 0; |
464 |
|
|
|
numLines = 0; |
|
465 |
int breakPoint; |
int breakPoint; |
466 |
for (int i = getStartOffset(); i < end;) |
for (int i = getStartOffset(); i < end;) |
467 |
{ |
{ |
507 |
* in model space |
* in model space |
508 |
* @throws BadLocationException if the given model position is invalid |
* @throws BadLocationException if the given model position is invalid |
509 |
*/ |
*/ |
510 |
public Shape modelToView(int pos, Shape a, Bias b) throws BadLocationException |
public Shape modelToView(int pos, Shape a, Bias b) |
511 |
|
throws BadLocationException |
512 |
{ |
{ |
513 |
Segment s = getLineBuffer(); |
Segment s = getLineBuffer(); |
514 |
int lineHeight = metrics.getHeight(); |
int lineHeight = metrics.getHeight(); |
541 |
{ |
{ |
542 |
// Shouldn't happen |
// Shouldn't happen |
543 |
} |
} |
544 |
rect.x += Utilities.getTabbedTextWidth(s, metrics, rect.x, WrappedPlainView.this, currLineStart); |
rect.x += Utilities.getTabbedTextWidth(s, metrics, rect.x, |
545 |
|
WrappedPlainView.this, |
546 |
|
currLineStart); |
547 |
return rect; |
return rect; |
548 |
} |
} |
549 |
// Increment rect.y so we're checking the next logical line |
// Increment rect.y so we're checking the next logical line |
620 |
currLineStart = currLineEnd; |
currLineStart = currLineEnd; |
621 |
} |
} |
622 |
} |
} |
623 |
|
|
624 |
|
/** |
625 |
|
* This method is called from insertUpdate and removeUpdate. |
626 |
|
* If the number of lines in the document has changed, just repaint |
627 |
|
* the whole thing (note, could improve performance by not repainting |
628 |
|
* anything above the changes). If the number of lines hasn't changed, |
629 |
|
* just repaint the given Rectangle. |
630 |
|
* @param a the Rectangle to repaint if the number of lines hasn't changed |
631 |
|
*/ |
632 |
|
void updateDamage (Rectangle a) |
633 |
|
{ |
634 |
|
int newNumLines = determineNumLines(); |
635 |
|
if (numLines != newNumLines) |
636 |
|
{ |
637 |
|
numLines = newNumLines; |
638 |
|
getContainer().repaint(); |
639 |
|
} |
640 |
|
else |
641 |
|
getContainer().repaint(a.x, a.y, a.width, a.height); |
642 |
|
} |
643 |
|
|
644 |
|
/** |
645 |
|
* This method is called when something is inserted into the Document |
646 |
|
* that this View is displaying. |
647 |
|
* |
648 |
|
* @param changes the DocumentEvent for the changes. |
649 |
|
* @param a the allocation of the View |
650 |
|
* @param f the ViewFactory used to rebuild |
651 |
|
*/ |
652 |
|
public void insertUpdate (DocumentEvent changes, Shape a, ViewFactory f) |
653 |
|
{ |
654 |
|
updateDamage((Rectangle)a); |
655 |
|
} |
656 |
|
|
657 |
|
/** |
658 |
|
* This method is called when something is removed from the Document |
659 |
|
* that this View is displaying. |
660 |
|
* |
661 |
|
* @param changes the DocumentEvent for the changes. |
662 |
|
* @param a the allocation of the View |
663 |
|
* @param f the ViewFactory used to rebuild |
664 |
|
*/ |
665 |
|
public void removeUpdate (DocumentEvent changes, Shape a, ViewFactory f) |
666 |
|
{ |
667 |
|
updateDamage((Rectangle)a); |
668 |
|
} |
669 |
} |
} |
670 |
} |
} |