AbstractShell.java

1
/*******************************************************************************
2
 * Copyhacked (H) 2012-2020.
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 about 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.shell;
12
13
import com.jsql.util.LogLevelUtil;
14
import com.jsql.view.swing.scrollpane.LightScrollPane;
15
import com.jsql.view.swing.util.UiUtil;
16
import org.apache.commons.lang3.StringUtils;
17
import org.apache.logging.log4j.LogManager;
18
import org.apache.logging.log4j.Logger;
19
20
import javax.swing.*;
21
import javax.swing.text.BadLocationException;
22
import javax.swing.text.Style;
23
import javax.swing.text.StyleConstants;
24
import javax.swing.text.StyledDocument;
25
import java.awt.*;
26
import java.awt.event.MouseMotionListener;
27
import java.net.MalformedURLException;
28
import java.net.URI;
29
import java.net.URISyntaxException;
30
import java.util.UUID;
31
32
/**
33
 * A Terminal completely built from swing text pane.
34
 */
35
public abstract class AbstractShell extends JTextPane {
36
    
37
    /**
38
     * Log4j logger sent to view.
39
     */
40
    private static final Logger LOGGER = LogManager.getRootLogger();
41
42
    /**
43
     * True if terminal is processing command.
44
     */
45
    private final boolean[] isEdited = {false};
46
47
    /**
48
     * Server name or IP to display on prompt.
49
     */
50
    private final String host;
51
52
    /**
53
     * User and password for database.
54
     */
55
    protected String[] loginPassword = null;
56
57
    private final UUID uuidShell;
58
    
59
    private final String urlShell;
60
61
    /**
62
     * Document used to append colored text.
63
     */
64
    private final transient StyledDocument styledDocument = this.getStyledDocument();
65
66
    /**
67
     * Style used for coloring text.
68
     */
69
    private final transient Style style = this.addStyle("Necrophagist's next album is 2014.", null);
70
71
    /**
72
     * Length of prompt.
73
     */
74
    private String prompt = StringUtils.EMPTY;
75
76
    /**
77
     * Text to display next caret.
78
     */
79
    private final String labelShell;
80
    
81
    /**
82
     * Build a shell instance.
83
     * @param uuidShell Unique identifier to discriminate beyond multiple opened terminals
84
     * @param urlShell URL of current shell
85
     * @param labelShell Type of shell to display on prompt
86
     * @throws MalformedURLException
87
     */
88
    protected AbstractShell(UUID uuidShell, String urlShell, String labelShell) throws MalformedURLException, URISyntaxException {
89
        
90
        this.uuidShell = uuidShell;
91
        this.urlShell = urlShell;
92
        this.labelShell = labelShell;
93
94
        var url = new URI(urlShell).toURL();
95
        this.host = url.getHost();
96
97 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setFont → NO_COVERAGE
        this.setFont(new Font(UiUtil.FONT_NAME_MONO_NON_ASIAN, Font.PLAIN, ((Font) UIManager.get("TextPane.font")).getSize()));
98 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setCaret → NO_COVERAGE
        this.setCaret(new BlockCaret());
99 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setBackground → NO_COVERAGE
        this.setBackground(Color.BLACK);
100 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setForeground → NO_COVERAGE
        this.setForeground(Color.LIGHT_GRAY);
101 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setBorder → NO_COVERAGE
        this.setBorder(BorderFactory.createEmptyBorder(0, 0, LightScrollPane.THUMB_SIZE, 0));
102
103 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::displayPrompt → NO_COVERAGE
        this.displayPrompt(true);
104
105 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setCursor → NO_COVERAGE
        this.setCursor(null);
106 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setTransferHandler → NO_COVERAGE
        this.setTransferHandler(null);
107 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::setHighlighter → NO_COVERAGE
        this.setHighlighter(null);
108
109 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::addMouseListener → NO_COVERAGE
        this.addMouseListener(new EmptyFocus(this));
110 1 1. <init> : removed call to com/jsql/view/swing/shell/AbstractShell::addKeyListener → NO_COVERAGE
        this.addKeyListener(new KeyAdapterTerminal(this));
111
    }
112
113
    /**
114
     * Run when cmd is validated.
115
     * @param cmd Command to execute
116
     * @param terminalID Unique ID for terminal instance
117
     * @param wbhPath URL of shell
118
     * @param arg Additional parameters (User and password for SQLShell)
119
     */
120
    public abstract void action(String cmd, UUID terminalID, String wbhPath, String... arg);
121
    
122
    /**
123
     * Update terminal and use default behavior.
124
     */
125
    public void reset() {
126
        
127
        this.isEdited[0] = false;
128 1 1. reset : removed call to com/jsql/view/swing/shell/AbstractShell::setEditable → NO_COVERAGE
        this.setEditable(true);
129 1 1. reset : removed call to com/jsql/view/swing/shell/AbstractShell::displayPrompt → NO_COVERAGE
        this.displayPrompt(false);
130 1 1. reset : removed call to com/jsql/view/swing/shell/AbstractShell::setCaretPosition → NO_COVERAGE
        this.setCaretPosition(this.getDocument().getLength());
131 1 1. reset : removed call to com/jsql/view/swing/shell/AbstractShell::setCursor → NO_COVERAGE
        this.setCursor(null);
132
    }
133
134
    /**
135
     * Add a text at the end of textpane.
136
     * @param string Text to add
137
     */
138
    public void append(String string) {
139
        try {
140
            var doc = this.getDocument();
141 1 1. append : removed call to javax/swing/text/Document::insertString → NO_COVERAGE
            doc.insertString(doc.getLength(), string, null);
142
            
143
        } catch (BadLocationException e) {
144
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
145
        }
146
    }
147
    
148
    /**
149
     * Append prompt to textpane, measure prompt the first time is used.
150
     * @param isAddingPrompt Should we measure prompt length?
151
     */
152
    public void displayPrompt(boolean isAddingPrompt) {
153
        
154 1 1. displayPrompt : removed call to javax/swing/text/StyleConstants::setUnderline → NO_COVERAGE
        StyleConstants.setUnderline(this.style, true);
155 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt("jsql", Color.LIGHT_GRAY, isAddingPrompt);
156 1 1. displayPrompt : removed call to javax/swing/text/StyleConstants::setUnderline → NO_COVERAGE
        StyleConstants.setUnderline(this.style, false);
157
158 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt(StringUtils.SPACE + this.labelShell, Color.LIGHT_GRAY, isAddingPrompt);
159 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt("[", new Color(50, 191, 50), isAddingPrompt);
160 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt(this.host, new Color(191, 191, 25), isAddingPrompt);
161 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt("]", new Color(50, 191, 50), isAddingPrompt);
162 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt(" >", new Color(191, 100, 100), isAddingPrompt);
163 1 1. displayPrompt : removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE
        this.appendPrompt(StringUtils.SPACE, Color.LIGHT_GRAY, isAddingPrompt);
164
    }
165
166
    /**
167
     * Add a colored string to the textpane, measure prompt at the same time.
168
     * @param string Text to append
169
     * @param color Color of text
170
     * @param isAddingPrompt Should we measure prompt length?
171
     */
172
    private void appendPrompt(String string, Color color, boolean isAddingPrompt) {
173
        try {
174 1 1. appendPrompt : removed call to javax/swing/text/StyleConstants::setForeground → NO_COVERAGE
            StyleConstants.setForeground(this.style, color);
175 1 1. appendPrompt : removed call to javax/swing/text/StyledDocument::insertString → NO_COVERAGE
            this.styledDocument.insertString(this.styledDocument.getLength(), string, this.style);
176
            
177 1 1. appendPrompt : negated conditional → NO_COVERAGE
            if (isAddingPrompt) {
178
                this.prompt += string;
179
            }
180
        } catch (BadLocationException e) {
181
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
182
        }
183
    }
184
185
    /**
186
     * NoWrap.
187
     */
188
    @Override
189
    public boolean getScrollableTracksViewportWidth() {
190 3 1. getScrollableTracksViewportWidth : changed conditional boundary → NO_COVERAGE
2. getScrollableTracksViewportWidth : negated conditional → NO_COVERAGE
3. getScrollableTracksViewportWidth : replaced boolean return with true for com/jsql/view/swing/shell/AbstractShell::getScrollableTracksViewportWidth → NO_COVERAGE
        return this.getUI().getPreferredSize(this).width <= this.getParent().getSize().width;
191
    }
192
193
    /**
194
     * Cancel every mouse movement processing like drag/drop.
195
     */
196
    @Override
197
    public synchronized void addMouseMotionListener(MouseMotionListener l) {
198
        // Do nothing
199
    }
200
201
    /**
202
     * Get index of line for current offset (generally cursor position).
203
     * @param offset Position on the line
204
     * @return Index of the line
205
     * @throws BadLocationException
206
     */
207
    public int getLineOfOffset(int offset) throws BadLocationException {
208
        
209
        var errorMsg = "Can't translate offset to line";
210
        var doc = this.getDocument();
211
        
212 2 1. getLineOfOffset : changed conditional boundary → NO_COVERAGE
2. getLineOfOffset : negated conditional → NO_COVERAGE
        if (offset < 0) {
213
            throw new BadLocationException(errorMsg, -1);
214 2 1. getLineOfOffset : negated conditional → NO_COVERAGE
2. getLineOfOffset : changed conditional boundary → NO_COVERAGE
        } else if (offset > doc.getLength()) {
215 1 1. getLineOfOffset : Replaced integer addition with subtraction → NO_COVERAGE
            throw new BadLocationException(errorMsg, doc.getLength() + 1);
216
        } else {
217
            
218
            var map = doc.getDefaultRootElement();
219 1 1. getLineOfOffset : replaced int return with 0 for com/jsql/view/swing/shell/AbstractShell::getLineOfOffset → NO_COVERAGE
            return map.getElementIndex(offset);
220
        }
221
    }
222
223
    /**
224
     * Get position of the beginning of the line.
225
     * @param line Index of the line
226
     * @return Offset of line
227
     * @throws BadLocationException
228
     */
229
    public int getLineStartOffset(int line) throws BadLocationException {
230
        
231
        var map = this.getDocument().getDefaultRootElement();
232
        
233 2 1. getLineStartOffset : changed conditional boundary → NO_COVERAGE
2. getLineStartOffset : negated conditional → NO_COVERAGE
        if (line < 0) {
234
            throw new BadLocationException("Negative line", -1);
235 2 1. getLineStartOffset : changed conditional boundary → NO_COVERAGE
2. getLineStartOffset : negated conditional → NO_COVERAGE
        } else if (line >= map.getElementCount()) {
236 1 1. getLineStartOffset : Replaced integer addition with subtraction → NO_COVERAGE
            throw new BadLocationException("No such line", this.getDocument().getLength() + 1);
237
        } else {
238
            
239
            var lineElem = map.getElement(line);
240 1 1. getLineStartOffset : replaced int return with 0 for com/jsql/view/swing/shell/AbstractShell::getLineStartOffset → NO_COVERAGE
            return lineElem.getStartOffset();
241
        }
242
    }
243
244
    
245
    // Getter and setter
246
    
247
    public boolean[] getIsEdited() {
248 1 1. getIsEdited : replaced return value with null for com/jsql/view/swing/shell/AbstractShell::getIsEdited → NO_COVERAGE
        return this.isEdited;
249
    }
250
251
    public UUID getUuidShell() {
252 1 1. getUuidShell : replaced return value with null for com/jsql/view/swing/shell/AbstractShell::getUuidShell → NO_COVERAGE
        return this.uuidShell;
253
    }
254
255
    public String getUrlShell() {
256 1 1. getUrlShell : replaced return value with "" for com/jsql/view/swing/shell/AbstractShell::getUrlShell → NO_COVERAGE
        return this.urlShell;
257
    }
258
259
    public String getPrompt() {
260 1 1. getPrompt : replaced return value with "" for com/jsql/view/swing/shell/AbstractShell::getPrompt → NO_COVERAGE
        return this.prompt;
261
    }
262
}

Mutations

97

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setFont → NO_COVERAGE

98

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setCaret → NO_COVERAGE

99

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setBackground → NO_COVERAGE

100

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setForeground → NO_COVERAGE

101

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setBorder → NO_COVERAGE

103

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::displayPrompt → NO_COVERAGE

105

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setCursor → NO_COVERAGE

106

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setTransferHandler → NO_COVERAGE

107

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setHighlighter → NO_COVERAGE

109

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::addMouseListener → NO_COVERAGE

110

1.1
Location : <init>
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::addKeyListener → NO_COVERAGE

128

1.1
Location : reset
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setEditable → NO_COVERAGE

129

1.1
Location : reset
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::displayPrompt → NO_COVERAGE

130

1.1
Location : reset
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setCaretPosition → NO_COVERAGE

131

1.1
Location : reset
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::setCursor → NO_COVERAGE

141

1.1
Location : append
Killed by : none
removed call to javax/swing/text/Document::insertString → NO_COVERAGE

154

1.1
Location : displayPrompt
Killed by : none
removed call to javax/swing/text/StyleConstants::setUnderline → NO_COVERAGE

155

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

156

1.1
Location : displayPrompt
Killed by : none
removed call to javax/swing/text/StyleConstants::setUnderline → NO_COVERAGE

158

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

159

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

160

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

161

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

162

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

163

1.1
Location : displayPrompt
Killed by : none
removed call to com/jsql/view/swing/shell/AbstractShell::appendPrompt → NO_COVERAGE

174

1.1
Location : appendPrompt
Killed by : none
removed call to javax/swing/text/StyleConstants::setForeground → NO_COVERAGE

175

1.1
Location : appendPrompt
Killed by : none
removed call to javax/swing/text/StyledDocument::insertString → NO_COVERAGE

177

1.1
Location : appendPrompt
Killed by : none
negated conditional → NO_COVERAGE

190

1.1
Location : getScrollableTracksViewportWidth
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getScrollableTracksViewportWidth
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : getScrollableTracksViewportWidth
Killed by : none
replaced boolean return with true for com/jsql/view/swing/shell/AbstractShell::getScrollableTracksViewportWidth → NO_COVERAGE

212

1.1
Location : getLineOfOffset
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getLineOfOffset
Killed by : none
negated conditional → NO_COVERAGE

214

1.1
Location : getLineOfOffset
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : getLineOfOffset
Killed by : none
changed conditional boundary → NO_COVERAGE

215

1.1
Location : getLineOfOffset
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

219

1.1
Location : getLineOfOffset
Killed by : none
replaced int return with 0 for com/jsql/view/swing/shell/AbstractShell::getLineOfOffset → NO_COVERAGE

233

1.1
Location : getLineStartOffset
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getLineStartOffset
Killed by : none
negated conditional → NO_COVERAGE

235

1.1
Location : getLineStartOffset
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : getLineStartOffset
Killed by : none
negated conditional → NO_COVERAGE

236

1.1
Location : getLineStartOffset
Killed by : none
Replaced integer addition with subtraction → NO_COVERAGE

240

1.1
Location : getLineStartOffset
Killed by : none
replaced int return with 0 for com/jsql/view/swing/shell/AbstractShell::getLineStartOffset → NO_COVERAGE

248

1.1
Location : getIsEdited
Killed by : none
replaced return value with null for com/jsql/view/swing/shell/AbstractShell::getIsEdited → NO_COVERAGE

252

1.1
Location : getUuidShell
Killed by : none
replaced return value with null for com/jsql/view/swing/shell/AbstractShell::getUuidShell → NO_COVERAGE

256

1.1
Location : getUrlShell
Killed by : none
replaced return value with "" for com/jsql/view/swing/shell/AbstractShell::getUrlShell → NO_COVERAGE

260

1.1
Location : getPrompt
Killed by : none
replaced return value with "" for com/jsql/view/swing/shell/AbstractShell::getPrompt → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.16.1