implement jterminal in source
This commit is contained in:
parent
18ce120984
commit
be72c2ff09
|
@ -0,0 +1,5 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
encoding//src/main/java=UTF-8
|
||||||
|
encoding//src/main/resources=UTF-8
|
||||||
|
encoding//src/test/java=UTF-8
|
||||||
|
encoding/<project>=UTF-8
|
|
@ -0,0 +1,5 @@
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.compliance=1.7
|
||||||
|
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
|
||||||
|
org.eclipse.jdt.core.compiler.source=1.7
|
|
@ -0,0 +1,4 @@
|
||||||
|
activeProfiles=
|
||||||
|
eclipse.preferences.version=1
|
||||||
|
resolveWorkspaceProjects=true
|
||||||
|
version=1
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link TerminalModel} which implements some common behaviour.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public abstract class AbstractTerminalModel implements TerminalModel {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void clear() {
|
||||||
|
int rows = getRows(), columns = getColumns();
|
||||||
|
for (int column = 0; column < columns; column++) {
|
||||||
|
for (int row = 0; row < rows; row++) {
|
||||||
|
setCell(column, row, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveCursorBack(int n) {
|
||||||
|
if (n < 0) {
|
||||||
|
throw new IllegalArgumentException("n must be positive");
|
||||||
|
}
|
||||||
|
int cursorColumn = getCursorColumn() - n;
|
||||||
|
if (cursorColumn < 0) {
|
||||||
|
cursorColumn = 0;
|
||||||
|
}
|
||||||
|
setCursorColumn(cursorColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveCursorForward(int n) {
|
||||||
|
if (n < 0) {
|
||||||
|
throw new IllegalArgumentException("n must be positive");
|
||||||
|
}
|
||||||
|
int columns = getColumns();
|
||||||
|
int cursorColumn = getCursorColumn() + n;
|
||||||
|
if (cursorColumn >= columns) {
|
||||||
|
cursorColumn = columns - 1;
|
||||||
|
}
|
||||||
|
setCursorColumn(cursorColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveCursorDown(int n) {
|
||||||
|
if (n < 0) {
|
||||||
|
throw new IllegalArgumentException("n must be positive");
|
||||||
|
}
|
||||||
|
int bufferSize = getBufferSize();
|
||||||
|
int cursorRow = getCursorRow() + n;
|
||||||
|
if (cursorRow >= bufferSize) {
|
||||||
|
cursorRow = bufferSize - 1;
|
||||||
|
}
|
||||||
|
setCursorRow(cursorRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moveCursorUp(int n) {
|
||||||
|
if (n < 0) {
|
||||||
|
throw new IllegalArgumentException("n must be positive");
|
||||||
|
}
|
||||||
|
int cursorRow = getCursorRow() - n;
|
||||||
|
if (cursorRow < 0) {
|
||||||
|
cursorRow = 0;
|
||||||
|
}
|
||||||
|
setCursorRow(cursorRow);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,198 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2016 Seth J. Morabito <web@loomcom.com>
|
||||||
|
* Portions Copyright (c) 2009-2011 Graham Edgecombe
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||||
|
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||||
|
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||||
|
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal;
|
||||||
|
|
||||||
|
import com.loomcom.symon.jterminal.vt100.Vt100TerminalModel;
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.Font;
|
||||||
|
import java.awt.FontMetrics;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.event.AdjustmentEvent;
|
||||||
|
import java.awt.event.AdjustmentListener;
|
||||||
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JScrollBar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Swing terminal emulation component
|
||||||
|
* @author Seth J. Morabito
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public class JTerminal extends JComponent {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 2871625194146986567L;
|
||||||
|
|
||||||
|
private int borderWidth = 0;
|
||||||
|
|
||||||
|
private JScrollBar scrollBar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The terminal emulation model
|
||||||
|
*/
|
||||||
|
private TerminalModel model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The font this terminal uses
|
||||||
|
*/
|
||||||
|
private Font font;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cell width in pixels
|
||||||
|
*/
|
||||||
|
private int cellWidth;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cell height in pixels
|
||||||
|
*/
|
||||||
|
private int cellHeight;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Max descender for font
|
||||||
|
*/
|
||||||
|
private int maxDescender;
|
||||||
|
|
||||||
|
public JTerminal(Font font) {
|
||||||
|
this(new Vt100TerminalModel(), font);
|
||||||
|
}
|
||||||
|
|
||||||
|
public JTerminal(TerminalModel model, Font font) {
|
||||||
|
setModel(model);
|
||||||
|
setFont(font);
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBorderWidth(int borderWidth) {
|
||||||
|
this.borderWidth = borderWidth;
|
||||||
|
revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getBorderWidth() {
|
||||||
|
return borderWidth;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFont(Font font) {
|
||||||
|
this.font = font;
|
||||||
|
setCellWidthAndHeight(font);
|
||||||
|
revalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Font getFont() {
|
||||||
|
return font;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setModel(TerminalModel model) {
|
||||||
|
if (model == null) {
|
||||||
|
throw new NullPointerException("model");
|
||||||
|
}
|
||||||
|
this.model = model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TerminalModel getModel() {
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(String str) {
|
||||||
|
if (str == null) {
|
||||||
|
throw new NullPointerException("str");
|
||||||
|
}
|
||||||
|
print(str.concat("\r\n"));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(String str) {
|
||||||
|
model.print(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dimension getMinimumSize() {
|
||||||
|
return new Dimension(model.getColumns() * cellWidth + borderWidth * 2,
|
||||||
|
model.getRows() * cellHeight + borderWidth * 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dimension getMaximumSize() {
|
||||||
|
return getMinimumSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Dimension getPreferredSize() {
|
||||||
|
return getMinimumSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void paint(Graphics g) {
|
||||||
|
g.setFont(font);
|
||||||
|
|
||||||
|
int width = model.getColumns();
|
||||||
|
int height = model.getBufferSize();
|
||||||
|
|
||||||
|
g.setColor(model.getDefaultBackgroundColor());
|
||||||
|
g.fillRect(0, 0, width * cellWidth + borderWidth * 2, height * cellHeight + borderWidth * 2);
|
||||||
|
|
||||||
|
int start = scrollBar == null ? 0 : scrollBar.getValue();
|
||||||
|
for (int y = start; y < height; y++) {
|
||||||
|
for (int x = 0; x < width; x++) {
|
||||||
|
TerminalCell cell = model.getCell(x, y);
|
||||||
|
boolean cursorHere = (model.getCursorRow() == y) && (model.getCursorColumn() == x);
|
||||||
|
|
||||||
|
if ((cursorHere) && (cell == null)) {
|
||||||
|
cell = new TerminalCell(' ', model.getDefaultBackgroundColor(), model.getDefaultForegroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cell != null) {
|
||||||
|
int px = x * cellWidth + borderWidth;
|
||||||
|
int py = (y - start) * cellHeight + borderWidth;
|
||||||
|
|
||||||
|
g.setColor(cursorHere ? cell.getForegroundColor() : cell.getBackgroundColor());
|
||||||
|
g.fillRect(px, py, cellWidth, cellHeight);
|
||||||
|
|
||||||
|
g.setColor(cursorHere ? cell.getBackgroundColor() : cell.getForegroundColor());
|
||||||
|
g.drawChars(new char[] { cell.getCharacter() }, 0, 1, px, py + cellHeight - maxDescender);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
setLayout(new BorderLayout(0, 0));
|
||||||
|
|
||||||
|
int rows = model.getRows();
|
||||||
|
int bufferSize = model.getBufferSize();
|
||||||
|
|
||||||
|
if (bufferSize > rows) {
|
||||||
|
scrollBar = new JScrollBar(1, 0, rows, 0, bufferSize + 1);
|
||||||
|
scrollBar.addAdjustmentListener(new AdjustmentListener() {
|
||||||
|
public void adjustmentValueChanged(AdjustmentEvent evt) {
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add("After", scrollBar);
|
||||||
|
}
|
||||||
|
|
||||||
|
repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setCellWidthAndHeight(Font font) {
|
||||||
|
FontMetrics metrics = getFontMetrics(font);
|
||||||
|
cellWidth = metrics.charWidth('W');
|
||||||
|
cellHeight = metrics.getHeight();
|
||||||
|
maxDescender = metrics.getMaxDescent();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,96 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a single terminal cell which contains a character, background
|
||||||
|
* color and foreground color.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class TerminalCell {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The character.
|
||||||
|
*/
|
||||||
|
private final char character;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The background color.
|
||||||
|
*/
|
||||||
|
private final Color backgroundColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The foreground color.
|
||||||
|
*/
|
||||||
|
private final Color foregroundColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a terminal cell with the specified character, background color
|
||||||
|
* and foreground color.
|
||||||
|
* @param character The character.
|
||||||
|
* @param backgroundColor The background color.
|
||||||
|
* @param foregroundColor The foreground color.
|
||||||
|
* @throws NullPointerException if the background or foreground color(s)
|
||||||
|
* are {@code null}.
|
||||||
|
*/
|
||||||
|
public TerminalCell(char character, Color backgroundColor, Color foregroundColor) {
|
||||||
|
if (backgroundColor == null) {
|
||||||
|
throw new NullPointerException("backgroundColor");
|
||||||
|
}
|
||||||
|
if (foregroundColor == null) {
|
||||||
|
throw new NullPointerException("foregroundColor");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.character = character;
|
||||||
|
this.backgroundColor = backgroundColor;
|
||||||
|
this.foregroundColor = foregroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the character.
|
||||||
|
* @return The character.
|
||||||
|
*/
|
||||||
|
public char getCharacter() {
|
||||||
|
return character;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the background color.
|
||||||
|
* @return The background color.
|
||||||
|
*/
|
||||||
|
public Color getBackgroundColor() {
|
||||||
|
return backgroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the foreground color.
|
||||||
|
* @return The foreground color.
|
||||||
|
*/
|
||||||
|
public Color getForegroundColor() {
|
||||||
|
return foregroundColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
import com.loomcom.symon.jterminal.bell.BellStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Model for terminals - defines methods for getting/setting cells, printing
|
||||||
|
* text to a terminal and getting the size of the terminal and buffer.
|
||||||
|
*/
|
||||||
|
public interface TerminalModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the bell strategy.
|
||||||
|
* @return The bell strategy.
|
||||||
|
*/
|
||||||
|
public BellStrategy getBellStrategy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the bell strategy.
|
||||||
|
* @param strategy The bell strategy.
|
||||||
|
* @throws NullPointerException if the strategy is {@code null}.
|
||||||
|
*/
|
||||||
|
public void setBellStrategy(BellStrategy strategy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the terminal.
|
||||||
|
*/
|
||||||
|
public void clear();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the cursor back n characters.
|
||||||
|
* @param n The number of characters.
|
||||||
|
* @throws IllegalArgumentException if n is not positive.
|
||||||
|
*/
|
||||||
|
public void moveCursorBack(int n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the cursor forward n characters.
|
||||||
|
* @param n The number of characters.
|
||||||
|
* @throws IllegalArgumentException if n is not positive.
|
||||||
|
*/
|
||||||
|
public void moveCursorForward(int n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the cursor down n characters.
|
||||||
|
* @param n The number of characters.
|
||||||
|
* @throws IllegalArgumentException if n is not positive.
|
||||||
|
*/
|
||||||
|
public void moveCursorDown(int n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the cursor up n characters.
|
||||||
|
* @param n The number of characters.
|
||||||
|
* @throws IllegalArgumentException if n is not positive.
|
||||||
|
*/
|
||||||
|
public void moveCursorUp(int n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a cell.
|
||||||
|
* @param column The column.
|
||||||
|
* @param row The row.
|
||||||
|
* @param cell The cell.
|
||||||
|
* @throws IndexOutOfBoundsException if the column and/or row number(s) are
|
||||||
|
* out of bounds.
|
||||||
|
*/
|
||||||
|
public void setCell(int column, int row, TerminalCell cell);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a cell.
|
||||||
|
* @param column The column.
|
||||||
|
* @param row The row.
|
||||||
|
* @return The cell.
|
||||||
|
* @throws IndexOutOfBoundsException if the column and/or row number(s) are
|
||||||
|
* out of bounds.
|
||||||
|
*/
|
||||||
|
public TerminalCell getCell(int column, int row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prints the specified string to the terminal at the cursor position,
|
||||||
|
* interpreting any escape sequences/special ASCII codes the model may
|
||||||
|
* support. Lines will be wrapped if necessary.
|
||||||
|
* @param str The string to print.
|
||||||
|
* @throws NullPointerException if the string is {@code null}.
|
||||||
|
*/
|
||||||
|
public void print(String str);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of columns.
|
||||||
|
* @return The number of columns.
|
||||||
|
*/
|
||||||
|
public int getColumns();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the number of rows.
|
||||||
|
* @return The number of rows.
|
||||||
|
*/
|
||||||
|
public int getRows();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the buffer size.
|
||||||
|
* @return The buffer size.
|
||||||
|
*/
|
||||||
|
public int getBufferSize();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cursor row.
|
||||||
|
* @return The cursor row.
|
||||||
|
*/
|
||||||
|
public int getCursorRow();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cursor row.
|
||||||
|
* @param row The cursor row.
|
||||||
|
* @throws IllegalArgumentException if the row is out of the valid range.
|
||||||
|
*/
|
||||||
|
public void setCursorRow(int row);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the cursor column.
|
||||||
|
* @return The cursor column.
|
||||||
|
*/
|
||||||
|
public int getCursorColumn();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the cursor column.
|
||||||
|
* @param column The cursor column.
|
||||||
|
* @throws IllegalArgumentException if the column is out of the valid range.
|
||||||
|
*/
|
||||||
|
public void setCursorColumn(int column);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default background color.
|
||||||
|
* @return The default background color.
|
||||||
|
*/
|
||||||
|
public Color getDefaultBackgroundColor();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the default foreground color.
|
||||||
|
* @return The default foreground color.
|
||||||
|
*/
|
||||||
|
public Color getDefaultForegroundColor();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.bell;
|
||||||
|
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link BellStrategy} which calls {@link Toolkit#beep()}.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class BeepBellStrategy implements BellStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void soundBell() {
|
||||||
|
Toolkit.getDefaultToolkit().beep();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.bell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A 'strategy' used to sound the bell (US-ASCII character {@code 7}).
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public interface BellStrategy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sounds the bell.
|
||||||
|
*/
|
||||||
|
public void soundBell();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.bell;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link BellStrategy} which does nothing.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class NopBellStrategy implements BellStrategy {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void soundBell() {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains bell strategy classes, which define how an application should
|
||||||
|
* respond to the US-ASCII {@code BEL} character.
|
||||||
|
*/
|
||||||
|
package com.loomcom.symon.jterminal.bell;
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains core JTerminal classes.
|
||||||
|
*/
|
||||||
|
package com.loomcom.symon.jterminal;
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.vt100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an ANSI control sequence.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class AnsiControlSequence {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The command character.
|
||||||
|
*/
|
||||||
|
private final char command;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The parameters.
|
||||||
|
*/
|
||||||
|
private final String[] parameters;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an ANSI control sequence with the specified command and
|
||||||
|
* parameters.
|
||||||
|
* @param command The command character.
|
||||||
|
* @param parameters The parameters array.
|
||||||
|
* @throws NullPointerException if the parameters array is {@code null}.
|
||||||
|
*/
|
||||||
|
public AnsiControlSequence(char command, String[] parameters) {
|
||||||
|
if (parameters == null) {
|
||||||
|
throw new NullPointerException("parameters");
|
||||||
|
}
|
||||||
|
this.command = command;
|
||||||
|
if (parameters.length == 1 && parameters[0].equals("")) {
|
||||||
|
this.parameters = new String[0];
|
||||||
|
} else {
|
||||||
|
this.parameters = parameters.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the command character.
|
||||||
|
* @return The command character.
|
||||||
|
*/
|
||||||
|
public char getCommand() {
|
||||||
|
return command;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the parameters array.
|
||||||
|
* @return The parameters array.
|
||||||
|
*/
|
||||||
|
public String[] getParameters() {
|
||||||
|
return parameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.vt100;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An interface which classes may use to listen to events from a
|
||||||
|
* {@link AnsiControlSequenceParser}.
|
||||||
|
*/
|
||||||
|
public interface AnsiControlSequenceListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a control sequence has been parsed.
|
||||||
|
* @param seq The control sequence.
|
||||||
|
*/
|
||||||
|
public void parsedControlSequence(AnsiControlSequence seq);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when a string has been parsed.
|
||||||
|
* @param str The string.
|
||||||
|
*/
|
||||||
|
public void parsedString(String str);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,156 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.vt100;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.Reader;
|
||||||
|
import java.io.StringReader;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class which parses {@link AnsiControlSequence}s from {@link String}(s).
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class AnsiControlSequenceParser {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The multi-byte control sequence introducer.
|
||||||
|
*/
|
||||||
|
private static final char[] MULTI_CSI = new char[] { 27, '[' };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The single-byte control sequence introducer.
|
||||||
|
*/
|
||||||
|
private static final char SINGLE_CSI = 155;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer of data from the last call to {@link #parse()}. This is
|
||||||
|
* populated with data if an escape sequence is not complete.
|
||||||
|
*/
|
||||||
|
private StringBuilder buffer = new StringBuilder();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ANSI control sequence listener.
|
||||||
|
*/
|
||||||
|
private final AnsiControlSequenceListener listener;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the ANSI control sequence parser.
|
||||||
|
* @param listener The listener.
|
||||||
|
*/
|
||||||
|
public AnsiControlSequenceParser(AnsiControlSequenceListener listener) {
|
||||||
|
this.listener = listener;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses the specified string.
|
||||||
|
* @param str The string to parse.
|
||||||
|
*/
|
||||||
|
public void parse(String str) {
|
||||||
|
if (buffer.length() > 0) {
|
||||||
|
str = buffer.toString().concat(str);
|
||||||
|
buffer = new StringBuilder();
|
||||||
|
}
|
||||||
|
Reader reader = new StringReader(str);
|
||||||
|
try {
|
||||||
|
try {
|
||||||
|
parse(reader);
|
||||||
|
} finally {
|
||||||
|
reader.close();
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
/* ignore */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses characters from the specified character reader.
|
||||||
|
* @param reader The character reader.
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
private void parse(Reader reader) throws IOException {
|
||||||
|
StringBuilder text = new StringBuilder();
|
||||||
|
int character;
|
||||||
|
while ((character = reader.read()) != -1) {
|
||||||
|
boolean introducedControlSequence = false;
|
||||||
|
if (character == SINGLE_CSI) {
|
||||||
|
introducedControlSequence = true;
|
||||||
|
} else if (character == MULTI_CSI[0]) {
|
||||||
|
int nextCharacter = reader.read();
|
||||||
|
if (nextCharacter == -1) {
|
||||||
|
buffer.append((char) character);
|
||||||
|
break;
|
||||||
|
} else if (nextCharacter == MULTI_CSI[1]) {
|
||||||
|
introducedControlSequence = true;
|
||||||
|
} else {
|
||||||
|
text.append((char) character);
|
||||||
|
text.append((char) nextCharacter);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
text.append((char) character);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (introducedControlSequence) {
|
||||||
|
if (text.length() > 0) {
|
||||||
|
listener.parsedString(text.toString());
|
||||||
|
text = new StringBuilder();
|
||||||
|
}
|
||||||
|
parseControlSequence(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (text.length() > 0) {
|
||||||
|
listener.parsedString(text.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses a control sequence.
|
||||||
|
* @param reader The character reader.
|
||||||
|
* @throws IOException if an I/O error occurs.
|
||||||
|
*/
|
||||||
|
private void parseControlSequence(Reader reader) throws IOException {
|
||||||
|
boolean finishedSequence = false;
|
||||||
|
StringBuilder parameters = new StringBuilder();
|
||||||
|
int character;
|
||||||
|
while ((character = reader.read()) != -1) {
|
||||||
|
if ((character >= 'a' && character <= 'z') || (character >= 'A' && character <= 'Z')) {
|
||||||
|
String[] array = parameters.toString().split(";");
|
||||||
|
AnsiControlSequence seq = new AnsiControlSequence((char) character, array);
|
||||||
|
listener.parsedControlSequence(seq);
|
||||||
|
|
||||||
|
finishedSequence = true;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
parameters.append((char) character);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!finishedSequence) {
|
||||||
|
// not an ideal solution if they used the two byte CSI, but it's
|
||||||
|
// easier and cleaner than keeping track of it
|
||||||
|
buffer.append((char) SINGLE_CSI);
|
||||||
|
buffer.append(parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.vt100;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains colors used by the SGR ANSI escape sequence.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
final class SgrColor {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of normal intensity colors.
|
||||||
|
*/
|
||||||
|
public static final Color[] COLOR_NORMAL = new Color[] {
|
||||||
|
new Color(0, 0, 0),
|
||||||
|
new Color(128, 0, 0),
|
||||||
|
new Color(0, 128, 0),
|
||||||
|
new Color(128, 128, 0),
|
||||||
|
new Color(0, 0, 128),
|
||||||
|
new Color(128, 0, 128),
|
||||||
|
new Color(0, 128, 128),
|
||||||
|
new Color(192, 192, 192)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An array of bright intensity colors.
|
||||||
|
*/
|
||||||
|
public static final Color[] COLOR_BRIGHT = new Color[] {
|
||||||
|
new Color(128, 128, 128),
|
||||||
|
new Color(255, 0, 0),
|
||||||
|
new Color(0, 255, 0),
|
||||||
|
new Color(255, 255, 0),
|
||||||
|
new Color(0, 0, 255),
|
||||||
|
new Color(0, 0, 255),
|
||||||
|
new Color(255, 0, 255),
|
||||||
|
new Color(0, 255, 255),
|
||||||
|
new Color(255, 255, 255)
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default private constructor to prevent instantiation.
|
||||||
|
*/
|
||||||
|
private SgrColor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,493 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon.jterminal.vt100;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
import com.loomcom.symon.jterminal.AbstractTerminalModel;
|
||||||
|
import com.loomcom.symon.jterminal.TerminalCell;
|
||||||
|
import com.loomcom.symon.jterminal.TerminalModel;
|
||||||
|
import com.loomcom.symon.jterminal.bell.BellStrategy;
|
||||||
|
import com.loomcom.symon.jterminal.bell.NopBellStrategy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A VT100/ANSI-compatible terminal model.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class Vt100TerminalModel extends AbstractTerminalModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A {@link AnsiControlSequenceListener} which modifies the
|
||||||
|
* {@link TerminalModel} appropriately when an event happens.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
private class Vt100Listener implements AnsiControlSequenceListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The saved cursor row.
|
||||||
|
*/
|
||||||
|
private int savedCursorRow = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The saved cursor column.
|
||||||
|
*/
|
||||||
|
private int savedCursorColumn = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parsedControlSequence(AnsiControlSequence seq) {
|
||||||
|
char command = seq.getCommand();
|
||||||
|
String[] parameters = seq.getParameters();
|
||||||
|
|
||||||
|
switch (command) {
|
||||||
|
case 'A':
|
||||||
|
case 'B':
|
||||||
|
case 'C':
|
||||||
|
case 'D':
|
||||||
|
int n = 1;
|
||||||
|
if (parameters.length == 1) {
|
||||||
|
n = Integer.parseInt(parameters[0]);
|
||||||
|
}
|
||||||
|
if (command == 'A') {
|
||||||
|
moveCursorUp(n);
|
||||||
|
} else if (command == 'B') {
|
||||||
|
moveCursorDown(n);
|
||||||
|
} else if (command == 'C') {
|
||||||
|
moveCursorForward(n);
|
||||||
|
} else if (command == 'D') {
|
||||||
|
moveCursorBack(n);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'E':
|
||||||
|
case 'F':
|
||||||
|
n = 1;
|
||||||
|
if (parameters.length == 1) {
|
||||||
|
n = Integer.parseInt(parameters[0]);
|
||||||
|
}
|
||||||
|
if (command == 'E') {
|
||||||
|
moveCursorDown(n);
|
||||||
|
} else if (command == 'F') {
|
||||||
|
moveCursorUp(n);
|
||||||
|
}
|
||||||
|
setCursorColumn(0);
|
||||||
|
break;
|
||||||
|
case 'G':
|
||||||
|
if (parameters.length == 1) {
|
||||||
|
n = Integer.parseInt(parameters[0]);
|
||||||
|
setCursorColumn(n - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
case 'f':
|
||||||
|
if (parameters.length == 2) {
|
||||||
|
n = 1;
|
||||||
|
int m = 1;
|
||||||
|
if (parameters[0].length() > 0) {
|
||||||
|
n = Integer.parseInt(parameters[0]);
|
||||||
|
}
|
||||||
|
if (parameters[1].length() > 0) {
|
||||||
|
m = Integer.parseInt(parameters[1]);
|
||||||
|
}
|
||||||
|
setCursorRow(n - 1);
|
||||||
|
setCursorColumn(m - 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'J':
|
||||||
|
n = 0;
|
||||||
|
if (parameters.length == 1) {
|
||||||
|
n = Integer.parseInt(parameters[0]);
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
int row = cursorRow;
|
||||||
|
int column = cursorColumn;
|
||||||
|
while(row < rows) {
|
||||||
|
while(column < columns) {
|
||||||
|
cells[row][column] = null;
|
||||||
|
column++;
|
||||||
|
}
|
||||||
|
column = 0;
|
||||||
|
row++;
|
||||||
|
}
|
||||||
|
} else if (n == 1) {
|
||||||
|
int row = cursorRow;
|
||||||
|
int column = cursorColumn;
|
||||||
|
while(row >= 0) {
|
||||||
|
while(column >= 0) {
|
||||||
|
cells[row][column] = null;
|
||||||
|
column--;
|
||||||
|
}
|
||||||
|
column = columns - 1;
|
||||||
|
row--;
|
||||||
|
}
|
||||||
|
} else if (n == 2) {
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'K':
|
||||||
|
n = 0;
|
||||||
|
if (parameters.length == 1) {
|
||||||
|
n = Integer.parseInt(parameters[0]);
|
||||||
|
}
|
||||||
|
if (n == 0) {
|
||||||
|
for (int row = cursorRow; row < rows; row++) {
|
||||||
|
cells[row][cursorColumn] = null;
|
||||||
|
}
|
||||||
|
} else if (n == 1) {
|
||||||
|
for (int row = cursorRow; row >= 0; row--) {
|
||||||
|
cells[row][cursorColumn] = null;
|
||||||
|
}
|
||||||
|
} else if (n == 2) {
|
||||||
|
for (int column = 0; column < columns; column++) {
|
||||||
|
cells[cursorRow][column] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
if (parameters.length == 0) {
|
||||||
|
parameters = new String[] { "0" };
|
||||||
|
}
|
||||||
|
for (String parameter : parameters) {
|
||||||
|
if (parameter.equals("0")) {
|
||||||
|
foregroundColor = DEFAULT_FOREGROUND_COLOR;
|
||||||
|
backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
backgroundBold = DEFAULT_BACKGROUND_BOLD;
|
||||||
|
foregroundBold = DEFAULT_FOREGROUND_BOLD;
|
||||||
|
} else if (parameter.equals("2")) {
|
||||||
|
backgroundBold = true;
|
||||||
|
foregroundBold = true;
|
||||||
|
} else if (parameter.equals("22")) {
|
||||||
|
backgroundBold = false;
|
||||||
|
foregroundBold = false;
|
||||||
|
} else if ((parameter.startsWith("3") || parameter.startsWith("4")) && parameter.length() == 2) {
|
||||||
|
int color = Integer.parseInt(parameter.substring(1));
|
||||||
|
if (parameter.startsWith("3")) {
|
||||||
|
foregroundColor = color;
|
||||||
|
} else if (parameter.startsWith("4")) {
|
||||||
|
backgroundColor = color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
if (savedCursorColumn != -1 && savedCursorRow != -1) {
|
||||||
|
cursorColumn = savedCursorColumn;
|
||||||
|
cursorRow = savedCursorRow;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 's':
|
||||||
|
savedCursorColumn = cursorColumn;
|
||||||
|
savedCursorRow = cursorRow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parsedString(String str) {
|
||||||
|
for (char ch : str.toCharArray()) {
|
||||||
|
switch (ch) {
|
||||||
|
case '\0':
|
||||||
|
continue;
|
||||||
|
case '\r':
|
||||||
|
cursorColumn = 0;
|
||||||
|
continue;
|
||||||
|
case '\n':
|
||||||
|
cursorRow++;
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
while ((++cursorColumn % TAB_WIDTH) != 0);
|
||||||
|
continue;
|
||||||
|
case 127:
|
||||||
|
if (cursorColumn > 0) {
|
||||||
|
cells[cursorRow][--cursorColumn] = null;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
case 7:
|
||||||
|
bellStrategy.soundBell();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursorColumn >= columns) {
|
||||||
|
cursorColumn = 0;
|
||||||
|
cursorRow++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cursorRow >= bufferSize) {
|
||||||
|
for (int i = 1; i < bufferSize; i++) {
|
||||||
|
System.arraycopy(cells[i], 0, cells[i - 1], 0, columns);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < columns; i++) {
|
||||||
|
cells[bufferSize - 1][i] = null;
|
||||||
|
}
|
||||||
|
cursorRow--;
|
||||||
|
}
|
||||||
|
|
||||||
|
Color back = backgroundBold ? SgrColor.COLOR_BRIGHT[backgroundColor] : SgrColor.COLOR_NORMAL[backgroundColor];
|
||||||
|
Color fore = foregroundBold ? SgrColor.COLOR_BRIGHT[foregroundColor] : SgrColor.COLOR_NORMAL[foregroundColor];
|
||||||
|
if (ch != '\n') {
|
||||||
|
cells[cursorRow][cursorColumn++] = new TerminalCell(ch, back, fore);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default number of columns.
|
||||||
|
*/
|
||||||
|
private static final int DEFAULT_COLUMNS = 80;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default number of rows.
|
||||||
|
*/
|
||||||
|
private static final int DEFAULT_ROWS = 25;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The tab width in characters.
|
||||||
|
*/
|
||||||
|
private static final int TAB_WIDTH = 8;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default foreground bold flag.
|
||||||
|
*/
|
||||||
|
private static final boolean DEFAULT_FOREGROUND_BOLD = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default background bold flag.
|
||||||
|
*/
|
||||||
|
private static final boolean DEFAULT_BACKGROUND_BOLD = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default foreground color.
|
||||||
|
*/
|
||||||
|
private static final int DEFAULT_FOREGROUND_COLOR = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default background color.
|
||||||
|
*/
|
||||||
|
private static final int DEFAULT_BACKGROUND_COLOR = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ANSI control sequence listener.
|
||||||
|
*/
|
||||||
|
private final AnsiControlSequenceListener listener = this.new Vt100Listener();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The ANSI control sequence parser.
|
||||||
|
*/
|
||||||
|
private final AnsiControlSequenceParser parser = new AnsiControlSequenceParser(listener);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current bell strategy.
|
||||||
|
*/
|
||||||
|
private BellStrategy bellStrategy = new NopBellStrategy();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The array of cells.
|
||||||
|
*/
|
||||||
|
private TerminalCell[][] cells;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of columns.
|
||||||
|
*/
|
||||||
|
private int columns;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The number of rows.
|
||||||
|
*/
|
||||||
|
private int rows;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The buffer size.
|
||||||
|
*/
|
||||||
|
private int bufferSize;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cursor row.
|
||||||
|
*/
|
||||||
|
private int cursorRow = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The cursor column.
|
||||||
|
*/
|
||||||
|
private int cursorColumn = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current foreground bold flag.
|
||||||
|
*/
|
||||||
|
private boolean foregroundBold = DEFAULT_FOREGROUND_BOLD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current background bold flag.
|
||||||
|
*/
|
||||||
|
private boolean backgroundBold = DEFAULT_BACKGROUND_BOLD;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current foreground color.
|
||||||
|
*/
|
||||||
|
private int foregroundColor = DEFAULT_FOREGROUND_COLOR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current background color.
|
||||||
|
*/
|
||||||
|
private int backgroundColor = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the terminal model with the default number of columns and rows,
|
||||||
|
* and the default buffer size.
|
||||||
|
*/
|
||||||
|
public Vt100TerminalModel() {
|
||||||
|
this(DEFAULT_COLUMNS, DEFAULT_ROWS);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the terminal model with the specified number of columns and
|
||||||
|
* rows. The buffer size is set to the number of rows.
|
||||||
|
* @param columns The number of columns.
|
||||||
|
* @param rows The number of rows.
|
||||||
|
* @throws IllegalArgumentException if the number of rows or columns is
|
||||||
|
* negative.
|
||||||
|
*/
|
||||||
|
public Vt100TerminalModel(int columns, int rows) {
|
||||||
|
this(columns, rows, rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates the terminal model with the specified number of columns and rows
|
||||||
|
* and the specified buffer size.
|
||||||
|
* @param columns The number of columns.
|
||||||
|
* @param rows The number of rows.
|
||||||
|
* @param bufferSize The buffer size.
|
||||||
|
* @throws IllegalArgumentException if the number of rows or columns is
|
||||||
|
* negative, or if the buffer size is less than the number of rows.
|
||||||
|
*/
|
||||||
|
public Vt100TerminalModel(int columns, int rows, int bufferSize) {
|
||||||
|
if (columns < 0 || rows < 0 || bufferSize < 0) {
|
||||||
|
throw new IllegalArgumentException("Zero or positive values only allowed for columns, rows and buffer size.");
|
||||||
|
}
|
||||||
|
if (bufferSize < rows) {
|
||||||
|
throw new IllegalArgumentException("The buffer is too small");
|
||||||
|
}
|
||||||
|
this.columns = columns;
|
||||||
|
this.rows = rows;
|
||||||
|
this.bufferSize = bufferSize;
|
||||||
|
init();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the terminal model.
|
||||||
|
*/
|
||||||
|
private void init() {
|
||||||
|
cells = new TerminalCell[bufferSize][columns];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCursorRow() {
|
||||||
|
return cursorRow;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCursorRow(int row) {
|
||||||
|
if (row < 0 || row >= bufferSize) {
|
||||||
|
throw new IllegalArgumentException("row out of range");
|
||||||
|
}
|
||||||
|
cursorRow = row;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getCursorColumn() {
|
||||||
|
return cursorColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCursorColumn(int column) {
|
||||||
|
if (column < 0 || column >= columns) {
|
||||||
|
throw new IllegalArgumentException("column out of range");
|
||||||
|
}
|
||||||
|
cursorColumn = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TerminalCell getCell(int column, int row) {
|
||||||
|
if (column < 0 || row < 0 || column >= columns || row >= bufferSize) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
return cells[row][column];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setCell(int column, int row, TerminalCell cell) {
|
||||||
|
if (column < 0 || row < 0 || column >= columns || row >= bufferSize) {
|
||||||
|
throw new IndexOutOfBoundsException();
|
||||||
|
}
|
||||||
|
cells[row][column] = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void print(String str) {
|
||||||
|
if (str == null) {
|
||||||
|
throw new NullPointerException("str");
|
||||||
|
}
|
||||||
|
parser.parse(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumns() {
|
||||||
|
return columns;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRows() {
|
||||||
|
return rows;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getBufferSize() {
|
||||||
|
return bufferSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BellStrategy getBellStrategy() {
|
||||||
|
return bellStrategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setBellStrategy(BellStrategy strategy) {
|
||||||
|
if (strategy == null) {
|
||||||
|
throw new NullPointerException("strategy");
|
||||||
|
}
|
||||||
|
this.bellStrategy = strategy;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getDefaultBackgroundColor() {
|
||||||
|
final int bg = DEFAULT_BACKGROUND_COLOR;
|
||||||
|
return DEFAULT_BACKGROUND_BOLD ? SgrColor.COLOR_BRIGHT[bg] : SgrColor.COLOR_NORMAL[bg];
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Color getDefaultForegroundColor() {
|
||||||
|
final int fg = DEFAULT_FOREGROUND_COLOR;
|
||||||
|
return DEFAULT_FOREGROUND_BOLD ? SgrColor.COLOR_BRIGHT[fg] : SgrColor.COLOR_NORMAL[fg];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains a terminal model roughly compatible with the VT100/ANSI standard.
|
||||||
|
*/
|
||||||
|
package com.loomcom.symon.jterminal.vt100;
|
||||||
|
|
|
@ -0,0 +1,231 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.loomcom.symon.jterminal.vt100.AnsiControlSequenceParser;
|
||||||
|
import com.loomcom.symon.jterminal.vt100.AnsiControlSequence;
|
||||||
|
import com.loomcom.symon.jterminal.vt100.AnsiControlSequenceListener;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test for the {@link AnsiControlSequenceParser} class.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class TestAnsiControlSequenceParser implements AnsiControlSequenceListener {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The current parser.
|
||||||
|
*/
|
||||||
|
private AnsiControlSequenceParser parser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The list of objects returned through the
|
||||||
|
* {@link AnsiControlSequenceListener} interface.
|
||||||
|
*/
|
||||||
|
private List<Object> objects = new ArrayList<Object>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the parser and object list.
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
objects.clear();
|
||||||
|
parser = new AnsiControlSequenceParser(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests a broken sequence with the single byte CSI.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBrokenSingleSequence() {
|
||||||
|
parser.parse(new String(new char[] { 155 }));
|
||||||
|
parser.parse(new String(new char[] { 'u' }));
|
||||||
|
|
||||||
|
assertEquals(1, objects.size());
|
||||||
|
|
||||||
|
Object obj = objects.get(0);
|
||||||
|
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||||
|
|
||||||
|
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||||
|
String[] params = seq.getParameters();
|
||||||
|
|
||||||
|
assertEquals('u', seq.getCommand());
|
||||||
|
assertEquals(0, params.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests a broken sequence with the double byte CSI.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBrokenDoubleSequence() {
|
||||||
|
char[] ch1 = { 27 };
|
||||||
|
char[] ch2 = { '[' };
|
||||||
|
char[] ch3 = { '3', '0', ';' };
|
||||||
|
char[] ch4 = { '4', '0', 'm' };
|
||||||
|
|
||||||
|
parser.parse(new String(ch1));
|
||||||
|
parser.parse(new String(ch2));
|
||||||
|
parser.parse(new String(ch3));
|
||||||
|
parser.parse(new String(ch4));
|
||||||
|
|
||||||
|
assertEquals(1, objects.size());
|
||||||
|
Object obj = objects.get(0);
|
||||||
|
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||||
|
|
||||||
|
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||||
|
String[] params = seq.getParameters();
|
||||||
|
|
||||||
|
assertEquals('m', seq.getCommand());
|
||||||
|
assertEquals(2, params.length);
|
||||||
|
assertEquals("30", params[0]);
|
||||||
|
assertEquals("40", params[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests an empty string.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEmpty() {
|
||||||
|
parser.parse("");
|
||||||
|
assertEquals(0, objects.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests a sequence embedded within some text.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testTextAndSequence() {
|
||||||
|
char[] ch = { 'h', 'i', 155, 'u', 'b', 'y', 'e' };
|
||||||
|
parser.parse(new String(ch));
|
||||||
|
|
||||||
|
assertEquals(3, objects.size());
|
||||||
|
|
||||||
|
Object o1 = objects.get(0);
|
||||||
|
Object o2 = objects.get(1);
|
||||||
|
Object o3 = objects.get(2);
|
||||||
|
|
||||||
|
assertEquals(String.class, o1.getClass());
|
||||||
|
assertEquals(AnsiControlSequence.class, o2.getClass());
|
||||||
|
assertEquals(String.class, o3.getClass());
|
||||||
|
|
||||||
|
assertEquals("hi", o1);
|
||||||
|
assertEquals("bye", o3);
|
||||||
|
|
||||||
|
AnsiControlSequence seq = (AnsiControlSequence) o2;
|
||||||
|
String[] params = seq.getParameters();
|
||||||
|
|
||||||
|
assertEquals(0, params.length);
|
||||||
|
assertEquals('u', seq.getCommand());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests parameters within a sequence.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParameters() {
|
||||||
|
char[] ch = { 155, '3', '0', ';', '4', '0', 'm' };
|
||||||
|
parser.parse(new String(ch));
|
||||||
|
|
||||||
|
assertEquals(1, objects.size());
|
||||||
|
Object obj = objects.get(0);
|
||||||
|
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||||
|
|
||||||
|
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||||
|
String[] params = seq.getParameters();
|
||||||
|
|
||||||
|
assertEquals('m', seq.getCommand());
|
||||||
|
assertEquals(2, params.length);
|
||||||
|
assertEquals("30", params[0]);
|
||||||
|
assertEquals("40", params[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests with plain text.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testText() {
|
||||||
|
parser.parse("Hello, World!");
|
||||||
|
|
||||||
|
assertEquals(1, objects.size());
|
||||||
|
Object obj = objects.get(0);
|
||||||
|
assertEquals(String.class, obj.getClass());
|
||||||
|
assertEquals(obj, "Hello, World!");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests with a single byte CSI.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSingleCsi() {
|
||||||
|
char[] ch = { 155, '6', 'n' };
|
||||||
|
parser.parse(new String(ch));
|
||||||
|
|
||||||
|
assertEquals(1, objects.size());
|
||||||
|
Object obj = objects.get(0);
|
||||||
|
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||||
|
|
||||||
|
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||||
|
String[] params = seq.getParameters();
|
||||||
|
assertEquals('n', seq.getCommand());
|
||||||
|
assertEquals(1, params.length);
|
||||||
|
assertEquals("6", params[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests with a double byte CSI.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testDoubleCsi() {
|
||||||
|
char[] ch = { 27, '[', 's' };
|
||||||
|
parser.parse(new String(ch));
|
||||||
|
|
||||||
|
assertEquals(1, objects.size());
|
||||||
|
Object obj = objects.get(0);
|
||||||
|
assertEquals(AnsiControlSequence.class, obj.getClass());
|
||||||
|
|
||||||
|
AnsiControlSequence seq = (AnsiControlSequence) obj;
|
||||||
|
String[] params = seq.getParameters();
|
||||||
|
assertEquals('s', seq.getCommand());
|
||||||
|
assertEquals(0, params.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parsedControlSequence(AnsiControlSequence seq) {
|
||||||
|
objects.add(seq);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void parsedString(String str) {
|
||||||
|
objects.add(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,233 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2009-2011 Graham Edgecombe.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to
|
||||||
|
* deal in the Software without restriction, including without limitation the
|
||||||
|
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||||
|
* sell copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
* DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.loomcom.symon;
|
||||||
|
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import java.awt.Color;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import com.loomcom.symon.jterminal.TerminalCell;
|
||||||
|
import com.loomcom.symon.jterminal.TerminalModel;
|
||||||
|
import com.loomcom.symon.jterminal.bell.BellStrategy;
|
||||||
|
import com.loomcom.symon.jterminal.vt100.Vt100TerminalModel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A test for the {@link Vt100TerminalModel} class.
|
||||||
|
* @author Graham Edgecombe
|
||||||
|
*/
|
||||||
|
public class TestVt100TerminalModel {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The terminal model.
|
||||||
|
*/
|
||||||
|
private TerminalModel model;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up the terminal model.
|
||||||
|
*/
|
||||||
|
@Before
|
||||||
|
public void setUp(){
|
||||||
|
model = new Vt100TerminalModel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the word wrapping.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testWordWrapping() {
|
||||||
|
int width = model.getColumns();
|
||||||
|
for (int i = 0; i < (width + 1); i++) {
|
||||||
|
model.print("h");
|
||||||
|
}
|
||||||
|
assertEquals('h', model.getCell(0, 1).getCharacter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests special ASCII characters.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSpecialCharacters() {
|
||||||
|
model.print("\u0000");
|
||||||
|
assertNull(model.getCell(0, 0));
|
||||||
|
|
||||||
|
model.print("a\rb\rc");
|
||||||
|
assertEquals('c', model.getCell(0, 0).getCharacter());
|
||||||
|
|
||||||
|
model.print("\na");
|
||||||
|
assertEquals('c', model.getCell(0, 0).getCharacter());
|
||||||
|
assertEquals('a', model.getCell(1, 1).getCharacter());
|
||||||
|
|
||||||
|
model.print("\u007F");
|
||||||
|
assertNull(model.getCell(0, 1));
|
||||||
|
|
||||||
|
model.print("A\tB");
|
||||||
|
assertEquals('B', model.getCell(8, 1).getCharacter());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the terminal scrolls once the buffer is full.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBuffer() {
|
||||||
|
model = new Vt100TerminalModel(model.getColumns(), 2, 2);
|
||||||
|
model.print("This is line one.\r\n");
|
||||||
|
model.print("This is line two. XXXXXX\r\n");
|
||||||
|
model.print("And this is line three!");
|
||||||
|
assertEquals('A', model.getCell(0, 1).getCharacter());
|
||||||
|
assertNull(model.getCell(23, 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the erase functionality.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testErase() {
|
||||||
|
model.print("Hello");
|
||||||
|
model.print("\u009B2J");
|
||||||
|
for (int i = 0; i < 5; i++) {
|
||||||
|
assertNull(model.getCell(i, 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests moving the cursor.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testMoveCursor() {
|
||||||
|
model.print("\u009B5B");
|
||||||
|
assertEquals(5, model.getCursorRow());
|
||||||
|
|
||||||
|
model.print("\u009B3A");
|
||||||
|
assertEquals(2, model.getCursorRow());
|
||||||
|
|
||||||
|
model.print("\u009B7C");
|
||||||
|
assertEquals(7, model.getCursorColumn());
|
||||||
|
|
||||||
|
model.print("\u009B4D");
|
||||||
|
assertEquals(3, model.getCursorColumn());
|
||||||
|
|
||||||
|
model.setCursorColumn(15);
|
||||||
|
model.setCursorRow(0);
|
||||||
|
|
||||||
|
model.print("\u009B3E");
|
||||||
|
assertEquals(0, model.getCursorColumn());
|
||||||
|
assertEquals(3, model.getCursorRow());
|
||||||
|
|
||||||
|
model.setCursorColumn(7);
|
||||||
|
|
||||||
|
model.print("\u009BF");
|
||||||
|
assertEquals(0, model.getCursorColumn());
|
||||||
|
assertEquals(2, model.getCursorRow());
|
||||||
|
|
||||||
|
model.print("\u009B4;8H");
|
||||||
|
assertEquals(3, model.getCursorRow());
|
||||||
|
assertEquals(7, model.getCursorColumn());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the SGR escape sequence.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSgr() {
|
||||||
|
model.print("\u009B2;33;41mX");
|
||||||
|
|
||||||
|
TerminalCell cell = model.getCell(0, 0);
|
||||||
|
assertNotNull(cell);
|
||||||
|
assertEquals('X', cell.getCharacter());
|
||||||
|
|
||||||
|
assertEquals(Color.RED, cell.getBackgroundColor());
|
||||||
|
assertEquals(Color.YELLOW, cell.getForegroundColor());
|
||||||
|
|
||||||
|
model.print("\u009B0m\rX");
|
||||||
|
|
||||||
|
cell = model.getCell(0, 0);
|
||||||
|
|
||||||
|
assertNotNull(cell);
|
||||||
|
assertEquals('X', cell.getCharacter());
|
||||||
|
|
||||||
|
assertEquals(model.getDefaultBackgroundColor(), cell.getBackgroundColor());
|
||||||
|
assertEquals(model.getDefaultForegroundColor(), cell.getForegroundColor());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests saving and restoring the cursor.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testSaveAndRestoreCursor() {
|
||||||
|
model.setCursorColumn(3);
|
||||||
|
model.setCursorRow(17);
|
||||||
|
|
||||||
|
model.print("\u009Bs");
|
||||||
|
|
||||||
|
model.setCursorColumn(5);
|
||||||
|
model.setCursorRow(23);
|
||||||
|
|
||||||
|
model.print("\u009Bu");
|
||||||
|
|
||||||
|
assertEquals(3, model.getCursorColumn());
|
||||||
|
assertEquals(17, model.getCursorRow());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests the printing of a simple message.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testPrint() {
|
||||||
|
model.print("Hi");
|
||||||
|
assertEquals('H', model.getCell(0, 0).getCharacter());
|
||||||
|
assertEquals('i', model.getCell(1, 0).getCharacter());
|
||||||
|
assertNull(model.getCell(2, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tests that the bell is sounded.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testBell() {
|
||||||
|
final int[] counter = new int[1];
|
||||||
|
|
||||||
|
BellStrategy strategy = new BellStrategy() {
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see com.loomcom.symon.jterminal.bell.BellStrategy#soundBell()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void soundBell() {
|
||||||
|
counter[0]++;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
model.setBellStrategy(strategy);
|
||||||
|
|
||||||
|
model.print("\u0007");
|
||||||
|
assertEquals(1, counter[0]);
|
||||||
|
|
||||||
|
model.print("Hello, \u0007World!\u0007\r\n");
|
||||||
|
assertEquals(3, counter[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue