View Javadoc
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 }