1 /*******************************************************************************
2 * Copyhacked (H) 2012-2025.
3 * This program and the accompanying materials
4 * are made available under no term at all, use it like
5 * you want, but share and discuss it
6 * every time possible with every body.
7 *
8 * Contributors:
9 * ron190 at ymail dot com - initial implementation
10 ******************************************************************************/
11 package com.jsql.view.swing.terminal.util;
12
13 import com.jsql.util.LogLevelUtil;
14 import org.apache.logging.log4j.LogManager;
15 import org.apache.logging.log4j.Logger;
16
17 import javax.swing.text.BadLocationException;
18 import javax.swing.text.DefaultCaret;
19 import javax.swing.text.JTextComponent;
20 import java.awt.*;
21
22 /**
23 * A caret in a block shape.
24 */
25 public class BlockCaret extends DefaultCaret {
26
27 private static final Logger LOGGER = LogManager.getRootLogger();
28
29 /**
30 * Create a caret shaped for terminal.
31 */
32 public BlockCaret() {
33 this.setBlinkRate(500); // half a second
34 }
35
36 @Override
37 protected synchronized void damage(Rectangle r) {
38 if (r == null) {
39 return;
40 }
41
42 // give values to x,y,width,height (inherited from java.awt.Rectangle)
43 this.x = r.x;
44 this.y = r.y;
45 this.height = r.height;
46
47 // A value for width was probably set by paint(), which we leave alone.
48 // But the first call to damage() precedes the first call to paint(), so
49 // in this case we must be prepared to set a valid width, or else
50 // paint()
51 // will receive a bogus clip area and caret will not get drawn properly.
52 if (this.width <= 0) {
53 this.width = this.getComponent().getWidth();
54 }
55
56 //Calls getComponent().repaint(x, y, width, height) to erase
57 this.repaint();
58
59 // previous location of caret. Sometimes one call isn't enough.
60 this.repaint();
61 }
62
63 @Override
64 public void paint(Graphics g) {
65 JTextComponent comp = this.getComponent();
66 if (comp == null) {
67 return;
68 }
69
70 int dot = this.getDot();
71 Rectangle r = null;
72 char dotChar;
73
74 try {
75 if (comp.modelToView2D(dot) != null) {
76 r = comp.modelToView2D(dot).getBounds();
77 }
78 dotChar = comp.getText(dot, 1).charAt(0);
79 } catch (BadLocationException e) {
80 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
81 return;
82 }
83
84 if (r == null) {
85 return;
86 }
87 if (Character.isWhitespace(dotChar)) {
88 dotChar = '_';
89 }
90 if (this.x != r.x || this.y != r.y) {
91 // paint() has been called directly, without a previous call to
92 // damage(), so do some cleanup. (This happens, for example, when
93 // the text component is resized.)
94 this.damage(r);
95 return;
96 }
97
98 g.setColor(new Color(0, 255, 0));
99 g.setXORMode(comp.getBackground()); // do this to draw in XOR mode
100
101 this.width = g.getFontMetrics().charWidth(dotChar);
102 if (this.isVisible()) {
103 g.fillRect(r.x, r.y, this.width, r.height);
104 }
105 }
106 }