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 org.apache.commons.lang3.StringUtils; | |
15 | import org.apache.logging.log4j.LogManager; | |
16 | import org.apache.logging.log4j.Logger; | |
17 | ||
18 | import javax.swing.*; | |
19 | import javax.swing.text.BadLocationException; | |
20 | import javax.swing.text.Element; | |
21 | import java.awt.event.InputEvent; | |
22 | import java.awt.event.KeyAdapter; | |
23 | import java.awt.event.KeyEvent; | |
24 | import java.util.ArrayList; | |
25 | import java.util.List; | |
26 | ||
27 | /** | |
28 | * Keyboard key processing for terminal. | |
29 | */ | |
30 | public class KeyAdapterTerminal extends KeyAdapter { | |
31 | | |
32 | /** | |
33 | * Log4j logger sent to view. | |
34 | */ | |
35 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
36 | ||
37 | /** | |
38 | * Terminal where keys are processed. | |
39 | */ | |
40 | private final AbstractShell terminal; | |
41 | ||
42 | /** | |
43 | * Past commands entered by user. | |
44 | */ | |
45 | private final List<String> commandsHistory = new ArrayList<>(); | |
46 | ||
47 | /** | |
48 | * Current position in array of past commands. | |
49 | */ | |
50 | private int indexCommandsHistory = 0; | |
51 | ||
52 | /** | |
53 | * Create a keyboard processor for a terminal. | |
54 | * @param terminal Terminal where keys are processed | |
55 | */ | |
56 | public KeyAdapterTerminal(AbstractShell terminal) { | |
57 | this.terminal = terminal; | |
58 | } | |
59 | ||
60 | @Override | |
61 | public void keyPressed(KeyEvent keyEvent) { | |
62 | try { | |
63 | final var root = this.terminal.getDocument().getDefaultRootElement(); | |
64 | final int caretPosition = this.terminal.getCaretPosition(); | |
65 | | |
66 | // Get current line | |
67 | int lineNumber = this.terminal.getLineOfOffset(caretPosition); | |
68 | | |
69 | // Cancel every user keyboard input if another command has just been sent | |
70 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
if (this.terminal.getIsEdited()[0]) { |
71 | | |
72 |
1
1. keyPressed : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
73 | return; | |
74 | } | |
75 | | |
76 | // Get user input | |
77 | final var command = new String[]{ StringUtils.EMPTY }; | |
78 | command[0] = this.terminal.getText( | |
79 | root.getElement(lineNumber).getStartOffset(), | |
80 |
1
1. keyPressed : Replaced integer subtraction with addition → NO_COVERAGE |
root.getElement(lineNumber).getEndOffset() - root.getElement(lineNumber).getStartOffset() |
81 | ) | |
82 | .replace(this.terminal.getPrompt(), StringUtils.EMPTY); | |
83 | | |
84 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) { // Validate user input ; disable text editing |
85 |
1
1. keyPressed : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal::runCommand → NO_COVERAGE |
this.runCommand(keyEvent, command); |
86 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_UP) { // Get previous command |
87 |
1
1. keyPressed : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal::appendPreviousCommand → NO_COVERAGE |
this.appendPreviousCommand(keyEvent, root, lineNumber, command); |
88 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_DOWN) { // Get next command |
89 |
1
1. keyPressed : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal::appendNextCommand → NO_COVERAGE |
this.appendNextCommand(keyEvent, root, lineNumber, command); |
90 |
2
1. keyPressed : negated conditional → NO_COVERAGE 2. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT || keyEvent.getKeyCode() == KeyEvent.VK_BACK_SPACE) { // Go to the left until prompt |
91 |
1
1. keyPressed : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal::moveCaretLeft → NO_COVERAGE |
this.moveCaretLeft(keyEvent, caretPosition, lineNumber); |
92 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_HOME) { // Get to the beginning of the line |
93 |
1
1. keyPressed : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal::moveCaretHome → NO_COVERAGE |
this.moveCaretHome(keyEvent, lineNumber); |
94 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (this.isKeyNotAllowed(keyEvent, caretPosition)) { |
95 |
1
1. keyPressed : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
96 |
3
1. keyPressed : negated conditional → NO_COVERAGE 2. keyPressed : Replaced bitwise AND with OR → NO_COVERAGE 3. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_C && (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) { |
97 |
1
1. keyPressed : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal::cancelCommand → NO_COVERAGE |
this.cancelCommand(keyEvent); |
98 | } | |
99 | } catch (BadLocationException e) { | |
100 | LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e); | |
101 | } | |
102 | } | |
103 | ||
104 | private boolean isKeyNotAllowed(KeyEvent keyEvent, final int caretPosition) { | |
105 |
1
1. isKeyNotAllowed : replaced boolean return with true for com/jsql/view/swing/shell/KeyAdapterTerminal::isKeyNotAllowed → NO_COVERAGE |
return |
106 | // Cancel the select all shortcut Ctrl+A | |
107 |
3
1. isKeyNotAllowed : negated conditional → NO_COVERAGE 2. isKeyNotAllowed : negated conditional → NO_COVERAGE 3. isKeyNotAllowed : Replaced bitwise AND with OR → NO_COVERAGE |
keyEvent.getKeyCode() == KeyEvent.VK_A && (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0 |
108 | // Cancel the *beep* sound if deleting while at the end of line | |
109 |
2
1. isKeyNotAllowed : negated conditional → NO_COVERAGE 2. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_DELETE && caretPosition == this.terminal.getDocument().getLength() |
110 |
4
1. isKeyNotAllowed : Replaced bitwise AND with OR → NO_COVERAGE 2. isKeyNotAllowed : negated conditional → NO_COVERAGE 3. isKeyNotAllowed : negated conditional → NO_COVERAGE 4. isKeyNotAllowed : Replaced bitwise AND with OR → NO_COVERAGE |
|| (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0 && (keyEvent.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0 |
111 |
1
1. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_PAGE_UP |
112 |
1
1. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_PAGE_DOWN |
113 |
1
1. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_TAB; |
114 | } | |
115 | ||
116 | private void cancelCommand(KeyEvent keyEvent) { | |
117 | | |
118 |
1
1. cancelCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
119 | | |
120 |
1
1. cancelCommand : removed call to com/jsql/view/swing/shell/AbstractShell::append → NO_COVERAGE |
this.terminal.append("\n"); |
121 |
1
1. cancelCommand : removed call to com/jsql/view/swing/shell/AbstractShell::reset → NO_COVERAGE |
this.terminal.reset(); |
122 | } | |
123 | ||
124 | private void moveCaretHome(KeyEvent keyEvent, int lineNumber) throws BadLocationException { | |
125 | | |
126 |
1
1. moveCaretHome : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
127 | | |
128 |
2
1. moveCaretHome : Replaced integer addition with subtraction → NO_COVERAGE 2. moveCaretHome : removed call to com/jsql/view/swing/shell/AbstractShell::setCaretPosition → NO_COVERAGE |
this.terminal.setCaretPosition(this.terminal.getLineStartOffset(lineNumber) + this.terminal.getPrompt().length()); |
129 | } | |
130 | ||
131 | private void moveCaretLeft(KeyEvent keyEvent, final int caretPosition, int lineNumber) throws BadLocationException { | |
132 | | |
133 |
1
1. moveCaretLeft : Replaced integer subtraction with addition → NO_COVERAGE |
int columnnum = caretPosition - this.terminal.getLineStartOffset(lineNumber); |
134 | ||
135 |
2
1. moveCaretLeft : negated conditional → NO_COVERAGE 2. moveCaretLeft : changed conditional boundary → NO_COVERAGE |
if (columnnum <= this.terminal.getPrompt().length()) { |
136 |
1
1. moveCaretLeft : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
137 | } | |
138 | } | |
139 | ||
140 | private void appendNextCommand( | |
141 | KeyEvent keyEvent, | |
142 | final Element root, | |
143 | int lineNumber, | |
144 | final String[] command | |
145 | ) throws BadLocationException { | |
146 | | |
147 |
1
1. appendNextCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
148 | | |
149 |
2
1. appendNextCommand : changed conditional boundary → NO_COVERAGE 2. appendNextCommand : negated conditional → NO_COVERAGE |
if (this.indexCommandsHistory < this.commandsHistory.size()) { |
150 |
1
1. appendNextCommand : Replaced integer addition with subtraction → NO_COVERAGE |
this.indexCommandsHistory++; |
151 | } | |
152 | | |
153 |
3
1. appendNextCommand : negated conditional → NO_COVERAGE 2. appendNextCommand : changed conditional boundary → NO_COVERAGE 3. appendNextCommand : negated conditional → NO_COVERAGE |
if (!this.commandsHistory.isEmpty() && this.indexCommandsHistory < this.commandsHistory.size()) { |
154 | | |
155 |
1
1. appendNextCommand : removed call to javax/swing/text/Document::remove → NO_COVERAGE |
this.terminal.getDocument().remove( |
156 |
1
1. appendNextCommand : Replaced integer addition with subtraction → NO_COVERAGE |
root.getElement(lineNumber).getStartOffset() + this.terminal.getPrompt().length(), |
157 |
1
1. appendNextCommand : Replaced integer subtraction with addition → NO_COVERAGE |
command[0].length() - 1 |
158 | ); | |
159 | | |
160 |
1
1. appendNextCommand : removed call to com/jsql/view/swing/shell/AbstractShell::append → NO_COVERAGE |
this.terminal.append(this.commandsHistory.get(this.indexCommandsHistory)); |
161 |
1
1. appendNextCommand : removed call to com/jsql/view/swing/shell/AbstractShell::setCaretPosition → NO_COVERAGE |
this.terminal.setCaretPosition(this.terminal.getDocument().getLength()); |
162 | } | |
163 | } | |
164 | ||
165 | private void appendPreviousCommand( | |
166 | KeyEvent keyEvent, | |
167 | final Element root, | |
168 | int lineNumber, | |
169 | final String[] command | |
170 | ) throws BadLocationException { | |
171 | | |
172 |
1
1. appendPreviousCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
173 | | |
174 |
2
1. appendPreviousCommand : negated conditional → NO_COVERAGE 2. appendPreviousCommand : changed conditional boundary → NO_COVERAGE |
if (this.indexCommandsHistory > 0) { |
175 |
1
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
this.indexCommandsHistory--; |
176 | } | |
177 | | |
178 |
1
1. appendPreviousCommand : negated conditional → NO_COVERAGE |
if (!this.commandsHistory.isEmpty()) { |
179 | | |
180 | if ( | |
181 |
2
1. appendPreviousCommand : changed conditional boundary → NO_COVERAGE 2. appendPreviousCommand : negated conditional → NO_COVERAGE |
this.commandsHistory.size() > 1 |
182 |
2
1. appendPreviousCommand : negated conditional → NO_COVERAGE 2. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
&& this.indexCommandsHistory == this.commandsHistory.size() - 1 |
183 |
1
1. appendPreviousCommand : negated conditional → NO_COVERAGE |
&& StringUtils.isNotEmpty(command[0].trim()) |
184 | ) { | |
185 |
1
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
this.indexCommandsHistory--; |
186 | } | |
187 | | |
188 |
1
1. appendPreviousCommand : removed call to javax/swing/text/Document::remove → NO_COVERAGE |
this.terminal.getDocument().remove( |
189 |
1
1. appendPreviousCommand : Replaced integer addition with subtraction → NO_COVERAGE |
root.getElement(lineNumber).getStartOffset() + this.terminal.getPrompt().length(), |
190 |
1
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
command[0].length() - 1 |
191 | ); | |
192 | | |
193 |
1
1. appendPreviousCommand : removed call to com/jsql/view/swing/shell/AbstractShell::append → NO_COVERAGE |
this.terminal.append(this.commandsHistory.get(this.indexCommandsHistory)); |
194 |
1
1. appendPreviousCommand : removed call to com/jsql/view/swing/shell/AbstractShell::setCaretPosition → NO_COVERAGE |
this.terminal.setCaretPosition(this.terminal.getDocument().getLength()); |
195 | } | |
196 | } | |
197 | ||
198 | private void runCommand(KeyEvent keyEvent, final String[] command) { | |
199 | | |
200 | this.terminal.getIsEdited()[0] = true; | |
201 |
1
1. runCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
202 |
1
1. runCommand : removed call to com/jsql/view/swing/shell/AbstractShell::setEditable → NO_COVERAGE |
this.terminal.setEditable(false); |
203 | | |
204 | // Populate cmd list for key up/down | |
205 |
1
1. runCommand : negated conditional → NO_COVERAGE |
if (StringUtils.isNotEmpty(command[0].trim())) { |
206 | | |
207 | this.commandsHistory.add(command[0].trim()); | |
208 | this.indexCommandsHistory = this.commandsHistory.size(); | |
209 | } | |
210 | | |
211 | // Thread to give back control of the GUI to the user (SwingUtilities does not) | |
212 | new SwingWorker<>() { | |
213 | | |
214 | @Override | |
215 | protected Object doInBackground() { | |
216 | | |
217 |
1
1. doInBackground : removed call to java/lang/Thread::setName → NO_COVERAGE |
Thread.currentThread().setName("SwingWorkerKeyAdapterTerminal"); |
218 | | |
219 | AbstractShell terminalCommand = KeyAdapterTerminal.this.terminal; | |
220 | | |
221 | // Inside Swing thread to avoid flickering | |
222 |
1
1. doInBackground : removed call to com/jsql/view/swing/shell/AbstractShell::append → NO_COVERAGE |
terminalCommand.append("\n"); |
223 | | |
224 |
1
1. doInBackground : negated conditional → NO_COVERAGE |
if (StringUtils.isNotEmpty(command[0].trim())) { |
225 | | |
226 |
1
1. doInBackground : removed call to com/jsql/view/swing/shell/AbstractShell::setCaretPosition → NO_COVERAGE |
terminalCommand.setCaretPosition(terminalCommand.getDocument().getLength()); |
227 | | |
228 |
1
1. doInBackground : removed call to com/jsql/view/swing/shell/AbstractShell::action → NO_COVERAGE |
terminalCommand.action( |
229 | command[0], | |
230 | terminalCommand.getUuidShell(), | |
231 | terminalCommand.getUrlShell(), | |
232 | terminalCommand.loginPassword | |
233 | ); | |
234 | } else { | |
235 |
1
1. doInBackground : removed call to com/jsql/view/swing/shell/AbstractShell::reset → NO_COVERAGE |
terminalCommand.reset(); |
236 | } | |
237 | | |
238 | return null; | |
239 | } | |
240 |
1
1. runCommand : removed call to com/jsql/view/swing/shell/KeyAdapterTerminal$1::execute → NO_COVERAGE |
}.execute(); |
241 | } | |
242 | } | |
Mutations | ||
70 |
1.1 |
|
72 |
1.1 |
|
80 |
1.1 |
|
84 |
1.1 |
|
85 |
1.1 |
|
86 |
1.1 |
|
87 |
1.1 |
|
88 |
1.1 |
|
89 |
1.1 |
|
90 |
1.1 2.2 |
|
91 |
1.1 |
|
92 |
1.1 |
|
93 |
1.1 |
|
94 |
1.1 |
|
95 |
1.1 |
|
96 |
1.1 2.2 3.3 |
|
97 |
1.1 |
|
105 |
1.1 |
|
107 |
1.1 2.2 3.3 |
|
109 |
1.1 2.2 |
|
110 |
1.1 2.2 3.3 4.4 |
|
111 |
1.1 |
|
112 |
1.1 |
|
113 |
1.1 |
|
118 |
1.1 |
|
120 |
1.1 |
|
121 |
1.1 |
|
126 |
1.1 |
|
128 |
1.1 2.2 |
|
133 |
1.1 |
|
135 |
1.1 2.2 |
|
136 |
1.1 |
|
147 |
1.1 |
|
149 |
1.1 2.2 |
|
150 |
1.1 |
|
153 |
1.1 2.2 3.3 |
|
155 |
1.1 |
|
156 |
1.1 |
|
157 |
1.1 |
|
160 |
1.1 |
|
161 |
1.1 |
|
172 |
1.1 |
|
174 |
1.1 2.2 |
|
175 |
1.1 |
|
178 |
1.1 |
|
181 |
1.1 2.2 |
|
182 |
1.1 2.2 |
|
183 |
1.1 |
|
185 |
1.1 |
|
188 |
1.1 |
|
189 |
1.1 |
|
190 |
1.1 |
|
193 |
1.1 |
|
194 |
1.1 |
|
201 |
1.1 |
|
202 |
1.1 |
|
205 |
1.1 |
|
217 |
1.1 |
|
222 |
1.1 |
|
224 |
1.1 |
|
226 |
1.1 |
|
228 |
1.1 |
|
235 |
1.1 |
|
240 |
1.1 |