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;
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      /**
28       * Log4j logger sent to view.
29       */
30      private static final Logger LOGGER = LogManager.getRootLogger();
31      
32      /**
33       * Create a caret shaped for terminal.
34       */
35      public BlockCaret() {
36          this.setBlinkRate(500);  // half a second
37      }
38  
39      @Override
40      protected synchronized void damage(Rectangle r) {
41          if (r == null) {
42              return;
43          }
44  
45          // give values to x,y,width,height (inherited from java.awt.Rectangle)
46          this.x = r.x;
47          this.y = r.y;
48          this.height = r.height;
49          
50          // A value for width was probably set by paint(), which we leave alone.
51          // But the first call to damage() precedes the first call to paint(), so
52          // in this case we must be prepared to set a valid width, or else
53          // paint()
54          // will receive a bogus clip area and caret will not get drawn properly.
55          if (this.width <= 0) {
56              this.width = this.getComponent().getWidth();
57          }
58  
59          //Calls getComponent().repaint(x, y, width, height) to erase
60          this.repaint();
61          
62          // previous location of caret. Sometimes one call isn't enough.
63          this.repaint();
64      }
65  
66      @Override
67      public void paint(Graphics g) {
68          JTextComponent comp = this.getComponent();
69          if (comp == null) {
70              return;
71          }
72  
73          int dot = this.getDot();
74          Rectangle r = null;
75          char dotChar;
76          
77          try {
78              if (comp.modelToView2D(dot) != null) {
79                  r = comp.modelToView2D(dot).getBounds();
80              }
81              dotChar = comp.getText(dot, 1).charAt(0);
82          } catch (BadLocationException e) {
83              LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
84              return;
85          }
86  
87          if (r == null) {
88              return;
89          }
90          if (Character.isWhitespace(dotChar)) {
91              dotChar = '_';
92          }
93          if (this.x != r.x || this.y != r.y) {
94              // paint() has been called directly, without a previous call to
95              // damage(), so do some cleanup. (This happens, for example, when
96              // the text component is resized.)
97              this.damage(r);
98              return;
99          }
100 
101         g.setColor(new Color(0, 255, 0));
102         g.setXORMode(comp.getBackground()); // do this to draw in XOR mode
103 
104         this.width = g.getFontMetrics().charWidth(dotChar);
105         if (this.isVisible()) {
106             g.fillRect(r.x, r.y, this.width, r.height);
107         }
108     }
109 }