mirror of
https://github.com/eclipse-cdt/cdt
synced 2025-07-01 06:05:24 +02:00
Merge R2_0_terminal_performance changes
This commit is contained in:
parent
e681ca63ff
commit
89a03bcb5a
46 changed files with 7139 additions and 29 deletions
|
@ -1,9 +1,9 @@
|
|||
feature@org.eclipse.tm.terminal=v20070913,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal-feature
|
||||
feature@org.eclipse.tm.terminal=v20070918,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal-feature
|
||||
feature@org.eclipse.tm.terminal.sdk=v20070808,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.sdk-feature
|
||||
feature@org.eclipse.tm.terminal.serial=v20070609,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.serial-feature
|
||||
feature@org.eclipse.tm.terminal.ssh=v20070808,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.ssh-feature
|
||||
feature@org.eclipse.tm.terminal.telnet=v20070609,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.telnet-feature
|
||||
feature@org.eclipse.tm.terminal.view=v20070913,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.view-feature
|
||||
feature@org.eclipse.tm.terminal.view=v20070918,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.view-feature
|
||||
plugin@org.eclipse.tm.terminal=v20070918,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal
|
||||
plugin@org.eclipse.tm.terminal.serial=v20070605,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.serial
|
||||
plugin@org.eclipse.tm.terminal.ssh=v20070909,:pserver:anonymous:none@dev.eclipse.org:/cvsroot/dsdp,,org.eclipse.tm.core/terminal/org.eclipse.tm.terminal.ssh
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<feature
|
||||
id="org.eclipse.tm.terminal"
|
||||
label="%featureName"
|
||||
version="1.0.0.qualifier"
|
||||
version="1.0.1.qualifier"
|
||||
provider-name="%providerName">
|
||||
|
||||
<description>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<feature
|
||||
id="org.eclipse.tm.terminal.view"
|
||||
label="%featureName"
|
||||
version="1.0.0.qualifier"
|
||||
version="1.0.1.qualifier"
|
||||
provider-name="%providerName">
|
||||
|
||||
<description>
|
||||
|
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tm.terminal.view;singleton:=true
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Version: 1.0.1.qualifier
|
||||
Bundle-Activator: org.eclipse.tm.internal.terminal.view.TerminalViewPlugin
|
||||
Bundle-Localization: plugin
|
||||
Require-Bundle: org.eclipse.ui,
|
||||
|
|
|
@ -28,11 +28,11 @@ import org.eclipse.jface.util.IPropertyChangeListener;
|
|||
import org.eclipse.jface.util.PropertyChangeEvent;
|
||||
import org.eclipse.jface.window.ApplicationWindow;
|
||||
import org.eclipse.jface.window.Window;
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.dnd.TextTransfer;
|
||||
import org.eclipse.swt.events.MenuEvent;
|
||||
import org.eclipse.swt.events.MenuListener;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Menu;
|
||||
import org.eclipse.tm.internal.terminal.actions.TerminalAction;
|
||||
|
@ -522,12 +522,12 @@ public class TerminalView extends ViewPart implements ITerminalView, ITerminalLi
|
|||
}
|
||||
|
||||
protected void setupContextMenus() {
|
||||
StyledText ctlText;
|
||||
Control ctlText;
|
||||
MenuManager menuMgr;
|
||||
Menu menu;
|
||||
TerminalContextMenuHandler contextMenuHandler;
|
||||
|
||||
ctlText = fCtlTerminal.getCtlText();
|
||||
ctlText = fCtlTerminal.getControl();
|
||||
menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
|
||||
menu = menuMgr.createContextMenu(ctlText);
|
||||
contextMenuHandler = new TerminalContextMenuHandler();
|
||||
|
@ -675,6 +675,7 @@ public class TerminalView extends ViewPart implements ITerminalView, ITerminalLi
|
|||
fMenuAboutToShow = true;
|
||||
updateEditCopy();
|
||||
updateEditCut();
|
||||
updateEditSelectAll();
|
||||
updateEditPaste();
|
||||
updateEditClearAll();
|
||||
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
org.eclipse.tm.terminal/debug = true
|
||||
org.eclipse.tm.terminal/debug/flag = true
|
||||
org.eclipse.tm.terminal/debug/filter = *
|
||||
org.eclipse.tm.terminal/debug/log/directory = /tmp/
|
||||
org.eclipse.tm.terminal/debug/log = true
|
||||
org.eclipse.tm.terminal/debug/log/error = true
|
||||
org.eclipse.tm.terminal/debug/log/info = false
|
||||
org.eclipse.tm.terminal/debug/log/char = false
|
||||
org.eclipse.tm.terminal/debug/log/buffer/size = false
|
||||
org.eclipse.tm.terminal/debug/log/VT100Backend = false
|
||||
org.eclipse.tm.terminal/debug/use_old_implementation = false
|
|
@ -1,7 +1,8 @@
|
|||
#Tue Jan 30 22:33:44 CET 2007
|
||||
#Thu Aug 09 03:12:08 CEST 2007
|
||||
eclipse.preferences.version=1
|
||||
instance/org.eclipse.core.net/org.eclipse.core.net.hasMigrated=true
|
||||
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
|
||||
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4
|
||||
org.eclipse.jdt.core.compiler.compliance=1.4
|
||||
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
|
||||
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
|
||||
|
@ -67,4 +68,4 @@ org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=di
|
|||
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
|
||||
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
|
||||
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
|
||||
org.eclipse.jdt.core.compiler.source=1.3
|
||||
org.eclipse.jdt.core.compiler.source=1.4
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
#Mon Jul 31 14:55:17 CEST 2006
|
||||
eclipse.preferences.version=1
|
||||
internal.default.compliance=user
|
|
@ -2,7 +2,7 @@ Manifest-Version: 1.0
|
|||
Bundle-ManifestVersion: 2
|
||||
Bundle-Name: %pluginName
|
||||
Bundle-SymbolicName: org.eclipse.tm.terminal; singleton:=true
|
||||
Bundle-Version: 1.0.0.qualifier
|
||||
Bundle-Version: 1.0.1.qualifier
|
||||
Bundle-Activator: org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin
|
||||
Bundle-Vendor: %providerName
|
||||
Bundle-Localization: plugin
|
||||
|
@ -13,4 +13,8 @@ Bundle-RequiredExecutionEnvironment: J2SE-1.4
|
|||
Bundle-ClassPath: .
|
||||
Export-Package: org.eclipse.tm.internal.terminal.control;x-friends:="org.eclipse.tm.terminal.view",
|
||||
org.eclipse.tm.internal.terminal.control.impl;x-internal:=true,
|
||||
org.eclipse.tm.internal.terminal.provisional.api;x-friends:="org.eclipse.tm.terminal.serial,org.eclipse.tm.terminal.ssh,org.eclipse.tm.terminal.telnet,org.eclipse.tm.terminal.view"
|
||||
org.eclipse.tm.internal.terminal.emulator;x-friends:="org.eclipse.tm.terminal.test",
|
||||
org.eclipse.tm.internal.terminal.model;x-friends:="org.eclipse.tm.terminal.test",
|
||||
org.eclipse.tm.internal.terminal.provisional.api;x-friends:="org.eclipse.tm.terminal.serial,org.eclipse.tm.terminal.ssh,org.eclipse.tm.terminal.telnet,org.eclipse.tm.terminal.view",
|
||||
org.eclipse.tm.internal.terminal.textcanvas;x-friends:="org.eclipse.tm.terminal.test",
|
||||
org.eclipse.tm.terminal.model
|
||||
|
|
|
@ -28,4 +28,6 @@ output.. = bin/
|
|||
src.includes = schema/,\
|
||||
README.txt,\
|
||||
about.html
|
||||
javacSource=1.4
|
||||
javacTarget=1.4
|
||||
|
|
@ -149,8 +149,8 @@ public class CommandInputFieldWithHistory implements ICommandInputField {
|
|||
}
|
||||
public void createControl(Composite parent,final ITerminalViewControl terminal) {
|
||||
fInputField=new Text(parent, SWT.SINGLE|SWT.BORDER);
|
||||
fInputField.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
|
||||
fInputField.setFont(terminal.getCtlText().getFont());
|
||||
fInputField.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
|
||||
fInputField.setFont(terminal.getFont());
|
||||
fInputField.addKeyListener(new KeyListener(){
|
||||
public void keyPressed(KeyEvent e) {
|
||||
if(e.keyCode=='\n' || e.keyCode=='\r') {
|
||||
|
|
|
@ -11,9 +11,9 @@
|
|||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.control;
|
||||
|
||||
import org.eclipse.swt.custom.StyledText;
|
||||
import org.eclipse.swt.dnd.Clipboard;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnectorInfo;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.TerminalState;
|
||||
|
||||
|
@ -24,7 +24,8 @@ import org.eclipse.tm.internal.terminal.provisional.api.TerminalState;
|
|||
public interface ITerminalViewControl {
|
||||
boolean isEmpty();
|
||||
void setFont(Font font);
|
||||
StyledText getCtlText();
|
||||
Font getFont();
|
||||
Control getControl();
|
||||
boolean isDisposed();
|
||||
void selectAll();
|
||||
void clearTerminal();
|
||||
|
@ -72,5 +73,4 @@ public interface ITerminalViewControl {
|
|||
* in the terminal view. -1 means unlimited.
|
||||
*/
|
||||
public void setBufferLineLimit(int bufferLineLimit);
|
||||
|
||||
}
|
|
@ -13,10 +13,15 @@ package org.eclipse.tm.internal.terminal.control;
|
|||
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.TerminalControl;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
|
||||
import org.eclipse.tm.internal.terminal.emulator.VT100TerminalControl;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnectorInfo;
|
||||
|
||||
public class TerminalViewControlFactory {
|
||||
public static ITerminalViewControl makeControl(ITerminalListener target, Composite wndParent, ITerminalConnectorInfo[] connectors) {
|
||||
return new TerminalControl(target, wndParent, connectors);
|
||||
if(TerminalPlugin.isOptionEnabled("org.eclipse.tm.terminal/debug/use_old_implementation")) //$NON-NLS-1$
|
||||
return new TerminalControl(target, wndParent, connectors);
|
||||
else
|
||||
return new VT100TerminalControl(target, wndParent, connectors);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -406,7 +406,12 @@ public class TerminalControl implements ITerminalControlForText, ITerminalContro
|
|||
|
||||
getTerminalText().fontChanged();
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
return getCtlText().getFont();
|
||||
}
|
||||
public Control getControl() {
|
||||
return fCtlText;
|
||||
}
|
||||
protected void setupControls(Composite parent) {
|
||||
// The Terminal view now aims to be an ANSI-conforming terminal emulator, so it
|
||||
// can't have a horizontal scroll bar (but a vertical one is ok). Also, do
|
||||
|
@ -423,8 +428,8 @@ public class TerminalControl implements ITerminalControlForText, ITerminalContro
|
|||
fWndParent.setLayout(layout);
|
||||
setCtlText(new StyledText(fWndParent, SWT.V_SCROLL));
|
||||
fCtlText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
//fCtlText.setWordWrap(false);
|
||||
|
||||
|
||||
fDisplay = getCtlText().getDisplay();
|
||||
fClipboard = new Clipboard(fDisplay);
|
||||
// fViewer.setDocument(new TerminalDocument());
|
||||
|
@ -515,7 +520,7 @@ public class TerminalControl implements ITerminalControlForText, ITerminalContro
|
|||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getCtlText()
|
||||
*/
|
||||
public StyledText getCtlText() {
|
||||
protected StyledText getCtlText() {
|
||||
return fCtlText;
|
||||
}
|
||||
|
||||
|
@ -856,4 +861,5 @@ public class TerminalControl implements ITerminalControlForText, ITerminalContro
|
|||
getTerminalText().setBufferLineLimit(bufferLineLimit);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,172 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.emulator;
|
||||
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
public interface IVT100EmulatorBackend {
|
||||
|
||||
/**
|
||||
* This method erases all text from the Terminal view. Including the history
|
||||
*/
|
||||
void clearAll();
|
||||
|
||||
/**
|
||||
* Sets the Dimensions of the addressable scroll space of the screen....
|
||||
* Keeps the cursor position relative to the bottom of the screen!
|
||||
* @param lines
|
||||
* @param cols
|
||||
*/
|
||||
void setDimensions(int lines, int cols);
|
||||
|
||||
/**
|
||||
* This method makes room for N characters on the current line at the cursor
|
||||
* position. Text under the cursor moves right without wrapping at the end
|
||||
* of the line.
|
||||
* 01234
|
||||
* 0 123
|
||||
*/
|
||||
void insertCharacters(int charactersToInsert);
|
||||
|
||||
/**
|
||||
* Erases from cursor to end of screen, including cursor position. Cursor does not move.
|
||||
*/
|
||||
void eraseToEndOfScreen();
|
||||
|
||||
/**
|
||||
* Erases from beginning of screen to cursor, including cursor position. Cursor does not move.
|
||||
*/
|
||||
void eraseToCursor();
|
||||
|
||||
/**
|
||||
* Erases complete display. All lines are erased and changed to single-width. Cursor does not move.
|
||||
*/
|
||||
void eraseAll();
|
||||
|
||||
/**
|
||||
* Erases complete line.
|
||||
*/
|
||||
void eraseLine();
|
||||
|
||||
/**
|
||||
* Erases from cursor to end of line, including cursor position.
|
||||
*/
|
||||
void eraseLineToEnd();
|
||||
|
||||
/**
|
||||
* Erases from beginning of line to cursor, including cursor position.
|
||||
*/
|
||||
void eraseLineToCursor();
|
||||
|
||||
/**
|
||||
* Inserts n lines at line with cursor. Lines displayed below cursor move down.
|
||||
* Lines moved past the bottom margin are lost. This sequence is ignored when
|
||||
* cursor is outside scrolling region.
|
||||
* @param n the number of lines to insert
|
||||
*/
|
||||
void insertLines(int n);
|
||||
|
||||
/**
|
||||
* Deletes n characters, starting with the character at cursor position.
|
||||
* When a character is deleted, all characters to the right of cursor move
|
||||
* left. This creates a space character at right margin. This character
|
||||
* has same character attribute as the last character moved left.
|
||||
* @param n
|
||||
* 012345
|
||||
* 0145xx
|
||||
*/
|
||||
void deleteCharacters(int n);
|
||||
|
||||
/**
|
||||
* Deletes n lines, starting at line with cursor. As lines are deleted,
|
||||
* lines displayed below cursor move up. Lines added to bottom of screen
|
||||
* have spaces with same character attributes as last line moved up. This
|
||||
* sequence is ignored when cursor is outside scrolling region.
|
||||
* @param n the number of lines to delete
|
||||
*/
|
||||
void deleteLines(int n);
|
||||
|
||||
Style getDefaultStyle();
|
||||
|
||||
void setDefaultStyle(Style defaultStyle);
|
||||
|
||||
Style getStyle();
|
||||
|
||||
/**
|
||||
* Sets the style to be used from now on
|
||||
* @param style
|
||||
*/
|
||||
void setStyle(Style style);
|
||||
|
||||
/**
|
||||
* This method displays a subset of the newly-received text in the Terminal
|
||||
* view, wrapping text at the right edge of the screen and overwriting text
|
||||
* when the cursor is not at the very end of the screen's text.
|
||||
* <p>
|
||||
*
|
||||
* There are never any ANSI control characters or escape sequences in the
|
||||
* text being displayed by this method (this includes newlines, carriage
|
||||
* returns, and tabs).
|
||||
* <p>
|
||||
*/
|
||||
void appendString(String buffer);
|
||||
|
||||
/**
|
||||
* Process a newline (Control-J) character. A newline (NL) character just
|
||||
* moves the cursor to the same column on the next line, creating new lines
|
||||
* when the cursor reaches the bottom edge of the terminal. This is
|
||||
* counter-intuitive, especially to UNIX programmers who are taught that
|
||||
* writing a single NL to a terminal is sufficient to move the cursor to the
|
||||
* first column of the next line, as if a carriage return (CR) and a NL were
|
||||
* written.
|
||||
* <p>
|
||||
*
|
||||
* UNIX terminals typically display a NL character as a CR followed by a NL
|
||||
* because the terminal device typically has the ONLCR attribute bit set
|
||||
* (see the termios(4) man page for details), which causes the terminal
|
||||
* device driver to translate NL to CR + NL on output. The terminal itself
|
||||
* (i.e., a hardware terminal or a terminal emulator, like xterm or this
|
||||
* code) _always_ interprets a CR to mean "move the cursor to the beginning
|
||||
* of the current line" and a NL to mean "move the cursor to the same column
|
||||
* on the next line".
|
||||
* <p>
|
||||
*/
|
||||
void processNewline();
|
||||
|
||||
/**
|
||||
* This method returns the relative line number of the line containing the
|
||||
* cursor. The returned line number is relative to the topmost visible line,
|
||||
* which has relative line number 0.
|
||||
*
|
||||
* @return The relative line number of the line containing the cursor.
|
||||
*/
|
||||
int getCursorLine();
|
||||
|
||||
int getCursorColumn();
|
||||
|
||||
/**
|
||||
* This method moves the cursor to the specified line and column. Parameter
|
||||
* <i>targetLine</i> is the line number of a screen line, so it has a
|
||||
* minimum value of 0 (the topmost screen line) and a maximum value of
|
||||
* heightInLines - 1 (the bottommost screen line). A line does not have to
|
||||
* contain any text to move the cursor to any column in that line.
|
||||
*/
|
||||
void setCursor(int targetLine, int targetColumn);
|
||||
|
||||
void setCursorColumn(int targetColumn);
|
||||
|
||||
void setCursorLine(int targetLine);
|
||||
|
||||
int getLines();
|
||||
|
||||
int getColumns();
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.emulator;
|
||||
|
||||
import java.io.PrintStream;
|
||||
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
public class VT100BackendTraceDecorator implements IVT100EmulatorBackend {
|
||||
final IVT100EmulatorBackend fBackend;
|
||||
final PrintStream fWriter;
|
||||
public VT100BackendTraceDecorator(IVT100EmulatorBackend backend, PrintStream out) {
|
||||
fBackend = backend;
|
||||
fWriter=out;
|
||||
}
|
||||
|
||||
public void appendString(String buffer) {
|
||||
fWriter.println("appendString(\""+buffer+"\")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.appendString(buffer);
|
||||
}
|
||||
|
||||
public void clearAll() {
|
||||
fWriter.println("clearAll()"); //$NON-NLS-1$
|
||||
fBackend.clearAll();
|
||||
}
|
||||
|
||||
public void deleteCharacters(int n) {
|
||||
fWriter.println("deleteCharacters("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.deleteCharacters(n);
|
||||
}
|
||||
|
||||
public void deleteLines(int n) {
|
||||
fWriter.println("deleteLines("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.deleteLines(n);
|
||||
}
|
||||
|
||||
public void eraseAll() {
|
||||
fWriter.println("eraseAll()"); //$NON-NLS-1$
|
||||
fBackend.eraseAll();
|
||||
}
|
||||
|
||||
public void eraseLine() {
|
||||
fWriter.println("eraseLine()"); //$NON-NLS-1$
|
||||
fBackend.eraseLine();
|
||||
}
|
||||
|
||||
public void eraseLineToCursor() {
|
||||
fWriter.println("eraseLineToCursor()"); //$NON-NLS-1$
|
||||
fBackend.eraseLineToCursor();
|
||||
}
|
||||
|
||||
public void eraseLineToEnd() {
|
||||
fWriter.println("eraseLineToEnd()"); //$NON-NLS-1$
|
||||
fBackend.eraseLineToEnd();
|
||||
}
|
||||
|
||||
public void eraseToCursor() {
|
||||
fWriter.println("eraseToCursor()"); //$NON-NLS-1$
|
||||
fBackend.eraseToCursor();
|
||||
}
|
||||
|
||||
public void eraseToEndOfScreen() {
|
||||
fWriter.println("eraseToEndOfScreen()"); //$NON-NLS-1$
|
||||
fBackend.eraseToEndOfScreen();
|
||||
}
|
||||
|
||||
public int getColumns() {
|
||||
return fBackend.getColumns();
|
||||
}
|
||||
|
||||
public int getCursorColumn() {
|
||||
return fBackend.getCursorColumn();
|
||||
}
|
||||
|
||||
public int getCursorLine() {
|
||||
return fBackend.getCursorLine();
|
||||
}
|
||||
|
||||
public Style getDefaultStyle() {
|
||||
return fBackend.getDefaultStyle();
|
||||
}
|
||||
|
||||
public int getLines() {
|
||||
return fBackend.getLines();
|
||||
}
|
||||
|
||||
public Style getStyle() {
|
||||
return fBackend.getStyle();
|
||||
}
|
||||
|
||||
public void insertCharacters(int charactersToInsert) {
|
||||
fWriter.println("insertCharacters("+charactersToInsert+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.insertCharacters(charactersToInsert);
|
||||
}
|
||||
|
||||
public void insertLines(int n) {
|
||||
fWriter.println("insertLines("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.insertLines(n);
|
||||
}
|
||||
|
||||
public void processNewline() {
|
||||
fWriter.println("processNewline()"); //$NON-NLS-1$
|
||||
fBackend.processNewline();
|
||||
}
|
||||
|
||||
public void setCursor(int targetLine, int targetColumn) {
|
||||
fWriter.println("setCursor("+targetLine+", "+targetColumn+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
fBackend.setCursor(targetLine, targetColumn);
|
||||
}
|
||||
|
||||
public void setCursorColumn(int targetColumn) {
|
||||
fWriter.println("setCursorColumn("+targetColumn+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.setCursorColumn(targetColumn);
|
||||
}
|
||||
|
||||
public void setCursorLine(int targetLine) {
|
||||
fWriter.println("setCursorLine("+targetLine+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.setCursorLine(targetLine);
|
||||
}
|
||||
|
||||
public void setDefaultStyle(Style defaultStyle) {
|
||||
fWriter.println("setDefaultStyle("+defaultStyle+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.setDefaultStyle(defaultStyle);
|
||||
}
|
||||
|
||||
public void setDimensions(int lines, int cols) {
|
||||
fWriter.println("setDimensions("+lines+","+cols+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
fBackend.setDimensions(lines, cols);
|
||||
}
|
||||
|
||||
public void setStyle(Style style) {
|
||||
fWriter.println("setStyle("+style+")"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
fBackend.setStyle(style);
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,387 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.emulator;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class VT100EmulatorBackend implements IVT100EmulatorBackend {
|
||||
|
||||
/**
|
||||
* This field holds the number of the column in which the cursor is
|
||||
* logically positioned. The leftmost column on the screen is column 0, and
|
||||
* column numbers increase to the right. The maximum value of this field is
|
||||
* {@link #widthInColumns} - 1. We track the cursor column using this field
|
||||
* to avoid having to recompute it repeatly using StyledText method calls.
|
||||
* <p>
|
||||
*
|
||||
* The StyledText widget that displays text has a vertical bar (called the
|
||||
* "caret") that appears _between_ character cells, but ANSI terminals have
|
||||
* the concept of a cursor that appears _in_ a character cell, so we need a
|
||||
* convention for which character cell the cursor logically occupies when
|
||||
* the caret is physically between two cells. The convention used in this
|
||||
* class is that the cursor is logically in column N when the caret is
|
||||
* physically positioned immediately to the _left_ of column N.
|
||||
* <p>
|
||||
*
|
||||
* When fCursorColumn is N, the next character output to the terminal appears
|
||||
* in column N. When a character is output to the rightmost column on a
|
||||
* given line (column widthInColumns - 1), the cursor moves to column 0 on
|
||||
* the next line after the character is drawn (this is how line wrapping is
|
||||
* implemented). If the cursor is in the bottommost line when line wrapping
|
||||
* occurs, the topmost visible line is scrolled off the top edge of the
|
||||
* screen.
|
||||
* <p>
|
||||
*/
|
||||
private int fCursorColumn;
|
||||
private int fCursorLine;
|
||||
private Style fDefaultStyle;
|
||||
private Style fStyle;
|
||||
int fLines;
|
||||
int fColumns;
|
||||
final private ITerminalTextData fTerminal;
|
||||
public VT100EmulatorBackend(ITerminalTextData terminal) {
|
||||
fTerminal=terminal;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#clearAll()
|
||||
*/
|
||||
public void clearAll() {
|
||||
synchronized (fTerminal) {
|
||||
// clear the history
|
||||
int n=fTerminal.getHeight();
|
||||
for (int line = 0; line < n; line++) {
|
||||
fTerminal.cleanLine(line);
|
||||
}
|
||||
fTerminal.setDimensions(fLines, fTerminal.getWidth());
|
||||
setStyle(getDefaultStyle());
|
||||
setCursor(0, 0);
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setDimensions(int, int)
|
||||
*/
|
||||
public void setDimensions(int lines, int cols) {
|
||||
synchronized (fTerminal) {
|
||||
if(lines==fLines && cols==fColumns)
|
||||
return; // nothing to do
|
||||
// cursor line from the bottom
|
||||
int cl=fLines-getCursorLine();
|
||||
int cc=getCursorColumn();
|
||||
|
||||
fLines=lines;
|
||||
fColumns=cols;
|
||||
// make the terminal at least as high as we need lines
|
||||
fTerminal.setDimensions(Math.max(fLines,fTerminal.getHeight()), fColumns);
|
||||
setCursor(fLines-cl, cc);
|
||||
}
|
||||
}
|
||||
|
||||
int toAbsoluteLine(int line) {
|
||||
synchronized (fTerminal) {
|
||||
return fTerminal.getHeight()-fLines+line;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#insertCharacters(int)
|
||||
*/
|
||||
public void insertCharacters(int charactersToInsert) {
|
||||
synchronized (fTerminal) {
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
int n=charactersToInsert;
|
||||
for (int col = fColumns-1; col >=fCursorColumn+n; col--) {
|
||||
char c=fTerminal.getChar(line, col-n);
|
||||
Style style=fTerminal.getStyle(line, col-n);
|
||||
fTerminal.setChar(line, col,c, style);
|
||||
}
|
||||
int last=Math.min(fCursorColumn+n, fColumns);
|
||||
for (int col = fCursorColumn; col <last; col++) {
|
||||
fTerminal.setChar(line, col,'\000', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseToEndOfScreen()
|
||||
*/
|
||||
public void eraseToEndOfScreen() {
|
||||
synchronized (fTerminal) {
|
||||
eraseLineToEnd();
|
||||
for (int line = toAbsoluteLine(fCursorLine+1); line < toAbsoluteLine(fLines); line++) {
|
||||
fTerminal.cleanLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseToCursor()
|
||||
*/
|
||||
public void eraseToCursor() {
|
||||
synchronized (fTerminal) {
|
||||
for (int line = toAbsoluteLine(0); line < toAbsoluteLine(fCursorLine); line++) {
|
||||
fTerminal.cleanLine(line);
|
||||
}
|
||||
eraseLineToCursor();
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseAll()
|
||||
*/
|
||||
public void eraseAll() {
|
||||
synchronized (fTerminal) {
|
||||
for (int line = toAbsoluteLine(0); line < toAbsoluteLine(fLines); line++) {
|
||||
fTerminal.cleanLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseLine()
|
||||
*/
|
||||
public void eraseLine() {
|
||||
synchronized (fTerminal) {
|
||||
fTerminal.cleanLine(toAbsoluteLine(fCursorLine));
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseLineToEnd()
|
||||
*/
|
||||
public void eraseLineToEnd() {
|
||||
synchronized (fTerminal) {
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
for (int col = fCursorColumn; col < fColumns; col++) {
|
||||
fTerminal.setChar(line, col, '\000', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#eraseLineToCursor()
|
||||
*/
|
||||
public void eraseLineToCursor() {
|
||||
synchronized (fTerminal) {
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
for (int col = 0; col <= fCursorColumn; col++) {
|
||||
fTerminal.setChar(line, col, '\000', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#insertLines(int)
|
||||
*/
|
||||
public void insertLines(int n) {
|
||||
synchronized (fTerminal) {
|
||||
if(!isCusorInScrollingRegion())
|
||||
return;
|
||||
assert n>0;
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
int nLines=fTerminal.getHeight()-line;
|
||||
fTerminal.scroll(line, nLines, n);
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#deleteCharacters(int)
|
||||
*/
|
||||
public void deleteCharacters(int n) {
|
||||
synchronized (fTerminal) {
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
for (int col = fCursorColumn+n; col < fColumns; col++) {
|
||||
char c=fTerminal.getChar(line, col);
|
||||
Style style=fTerminal.getStyle(line, col);
|
||||
fTerminal.setChar(line, col-n,c, style);
|
||||
}
|
||||
int first=Math.max(fCursorColumn, fColumns-n);
|
||||
for (int col = first; col <fColumns; col++) {
|
||||
fTerminal.setChar(line, col,'\000', null);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#deleteLines(int)
|
||||
*/
|
||||
public void deleteLines(int n) {
|
||||
synchronized (fTerminal) {
|
||||
if(!isCusorInScrollingRegion())
|
||||
return;
|
||||
assert n>0;
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
int nLines=fTerminal.getHeight()-line;
|
||||
fTerminal.scroll(line, nLines, -n);
|
||||
}
|
||||
}
|
||||
private boolean isCusorInScrollingRegion() {
|
||||
// TODO Auto-generated method stub
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getDefaultStyle()
|
||||
*/
|
||||
public Style getDefaultStyle() {
|
||||
synchronized (fTerminal) {
|
||||
return fDefaultStyle;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setDefaultStyle(org.eclipse.tm.terminal.model.Style)
|
||||
*/
|
||||
public void setDefaultStyle(Style defaultStyle) {
|
||||
synchronized (fTerminal) {
|
||||
fDefaultStyle = defaultStyle;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getStyle()
|
||||
*/
|
||||
public Style getStyle() {
|
||||
synchronized (fTerminal) {
|
||||
if(fStyle==null)
|
||||
return fDefaultStyle;
|
||||
return fStyle;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setStyle(org.eclipse.tm.terminal.model.Style)
|
||||
*/
|
||||
public void setStyle(Style style) {
|
||||
synchronized (fTerminal) {
|
||||
fStyle=style;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#appendString(java.lang.String)
|
||||
*/
|
||||
public void appendString(String buffer) {
|
||||
synchronized (fTerminal) {
|
||||
char[] chars=buffer.toCharArray();
|
||||
int line=toAbsoluteLine(fCursorLine);
|
||||
int i=0;
|
||||
while (i < chars.length) {
|
||||
int n=Math.min(fColumns-fCursorColumn,chars.length-i);
|
||||
fTerminal.setChars(line, fCursorColumn, chars, i, n, fStyle);
|
||||
int col=fCursorColumn+n;
|
||||
i+=n;
|
||||
// wrap needed?
|
||||
if(col>=fColumns) {
|
||||
doNewline();
|
||||
line=toAbsoluteLine(fCursorLine);
|
||||
setCursorColumn(0);
|
||||
} else {
|
||||
setCursorColumn(col);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* MUST be called from a synchronized block!
|
||||
*/
|
||||
private void doNewline() {
|
||||
if(fCursorLine+1>=fLines) {
|
||||
int h=fTerminal.getHeight();
|
||||
fTerminal.addLine();
|
||||
if(h!=fTerminal.getHeight())
|
||||
setCursorLine(fCursorLine+1);
|
||||
} else {
|
||||
setCursorLine(fCursorLine+1);
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#processNewline()
|
||||
*/
|
||||
public void processNewline() {
|
||||
synchronized (fTerminal) {
|
||||
doNewline();
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getCursorLine()
|
||||
*/
|
||||
public int getCursorLine() {
|
||||
synchronized (fTerminal) {
|
||||
return fCursorLine;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getCursorColumn()
|
||||
*/
|
||||
public int getCursorColumn() {
|
||||
synchronized (fTerminal) {
|
||||
return fCursorColumn;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursor(int, int)
|
||||
*/
|
||||
public void setCursor(int targetLine, int targetColumn) {
|
||||
synchronized (fTerminal) {
|
||||
setCursorLine(targetLine);
|
||||
setCursorColumn(targetColumn);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursorColumn(int)
|
||||
*/
|
||||
public void setCursorColumn(int targetColumn) {
|
||||
synchronized (fTerminal) {
|
||||
if(targetColumn<0)
|
||||
targetColumn=0;
|
||||
else if(targetColumn>=fColumns)
|
||||
targetColumn=fColumns-1;
|
||||
fCursorColumn=targetColumn;
|
||||
// We make the assumption that nobody is changing the
|
||||
// terminal cursor except this class!
|
||||
// This assumption gives a huge performance improvement
|
||||
fTerminal.setCursorColumn(targetColumn);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursorLine(int)
|
||||
*/
|
||||
public void setCursorLine(int targetLine) {
|
||||
synchronized (fTerminal) {
|
||||
if(targetLine<0)
|
||||
targetLine=0;
|
||||
else if(targetLine>=fLines)
|
||||
targetLine=fLines-1;
|
||||
fCursorLine=targetLine;
|
||||
// We make the assumption that nobody is changing the
|
||||
// terminal cursor except this class!
|
||||
// This assumption gives a huge performance improvement
|
||||
fTerminal.setCursorLine(toAbsoluteLine(targetLine));
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getLines()
|
||||
*/
|
||||
public int getLines() {
|
||||
synchronized (fTerminal) {
|
||||
return fLines;
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getColumns()
|
||||
*/
|
||||
public int getColumns() {
|
||||
synchronized (fTerminal) {
|
||||
return fColumns;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,906 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2003, 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Initial Contributors:
|
||||
* The following Wind River employees contributed to the Terminal component
|
||||
* that contains this file: Chris Thew, Fran Litterio, Stephen Lamb,
|
||||
* Helmut Haigermoser and Ted Williams.
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - split into core, view and connector plugins
|
||||
* Martin Oberhuber (Wind River) - fixed copyright headers and beautified
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.emulator;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.SocketException;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
import org.eclipse.core.runtime.IStatus;
|
||||
import org.eclipse.core.runtime.Status;
|
||||
import org.eclipse.core.runtime.jobs.Job;
|
||||
import org.eclipse.jface.dialogs.MessageDialog;
|
||||
import org.eclipse.jface.resource.JFaceResources;
|
||||
import org.eclipse.osgi.util.NLS;
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.dnd.Clipboard;
|
||||
import org.eclipse.swt.dnd.TextTransfer;
|
||||
import org.eclipse.swt.events.FocusEvent;
|
||||
import org.eclipse.swt.events.FocusListener;
|
||||
import org.eclipse.swt.events.KeyAdapter;
|
||||
import org.eclipse.swt.events.KeyEvent;
|
||||
import org.eclipse.swt.events.KeyListener;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.layout.GridData;
|
||||
import org.eclipse.swt.layout.GridLayout;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Control;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.Shell;
|
||||
import org.eclipse.tm.internal.terminal.control.ICommandInputField;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalListener;
|
||||
import org.eclipse.tm.internal.terminal.control.ITerminalViewControl;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.ITerminalControlForText;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.TerminalMessages;
|
||||
import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnectorInfo;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.Logger;
|
||||
import org.eclipse.tm.internal.terminal.provisional.api.TerminalState;
|
||||
import org.eclipse.tm.internal.terminal.textcanvas.ITextCanvasModel;
|
||||
import org.eclipse.tm.internal.terminal.textcanvas.PipedInputStream;
|
||||
import org.eclipse.tm.internal.terminal.textcanvas.PollingTextCanvasModel;
|
||||
import org.eclipse.tm.internal.terminal.textcanvas.TextCanvas;
|
||||
import org.eclipse.tm.internal.terminal.textcanvas.TextLineRenderer;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.TerminalTextDataFactory;
|
||||
import org.eclipse.ui.PlatformUI;
|
||||
import org.eclipse.ui.contexts.IContextActivation;
|
||||
import org.eclipse.ui.contexts.IContextService;
|
||||
import org.eclipse.ui.keys.IBindingService;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class was originally written to use nested classes, which unfortunately makes
|
||||
* this source file larger and more complex than it needs to be. In particular, the
|
||||
* methods in the nested classes directly access the fields of the enclosing class.
|
||||
* One day we should pull the nested classes out into their own source files (but still
|
||||
* in this package).
|
||||
*
|
||||
* @author Chris Thew <chris.thew@windriver.com>
|
||||
*/
|
||||
public class VT100TerminalControl implements ITerminalControlForText, ITerminalControl, ITerminalViewControl
|
||||
{
|
||||
protected final static String[] LINE_DELIMITERS = { "\n" }; //$NON-NLS-1$
|
||||
|
||||
/**
|
||||
* This field holds a reference to a TerminalText object that performs all ANSI
|
||||
* text processing on data received from the remote host and controls how text is
|
||||
* displayed using the view's StyledText widget.
|
||||
*/
|
||||
private VT100Emulator fTerminalText;
|
||||
private Display fDisplay;
|
||||
private TextCanvas fCtlText;
|
||||
private Composite fWndParent;
|
||||
private Clipboard fClipboard;
|
||||
private KeyListener fKeyHandler;
|
||||
private ITerminalListener fTerminalListener;
|
||||
private String fMsg = ""; //$NON-NLS-1$
|
||||
private FocusListener fFocusListener;
|
||||
private ITerminalConnectorInfo fConnectorInfo;
|
||||
private final ITerminalConnectorInfo[] fConnectors;
|
||||
PipedInputStream fInputStream;
|
||||
|
||||
private ICommandInputField fCommandInputField;
|
||||
|
||||
private volatile TerminalState fState;
|
||||
|
||||
private ITerminalTextData fTerminalModel;
|
||||
|
||||
volatile private Job fJob;
|
||||
|
||||
public VT100TerminalControl(ITerminalListener target, Composite wndParent, ITerminalConnectorInfo[] connectors) {
|
||||
fConnectors=connectors;
|
||||
fTerminalListener=target;
|
||||
fTerminalModel=TerminalTextDataFactory.makeTerminalTextData();
|
||||
fTerminalModel.setDimensions(24, 80);
|
||||
fTerminalModel.setMaxHeight(1000);
|
||||
fInputStream=new PipedInputStream(8*1024);
|
||||
fTerminalText=new VT100Emulator(fTerminalModel,this,fInputStream);
|
||||
|
||||
setupTerminal(wndParent);
|
||||
}
|
||||
|
||||
public ITerminalConnectorInfo[] getConnectors() {
|
||||
return fConnectors;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#copy()
|
||||
*/
|
||||
public void copy() {
|
||||
getCtlText().copy();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#paste()
|
||||
*/
|
||||
public void paste() {
|
||||
TextTransfer textTransfer = TextTransfer.getInstance();
|
||||
String strText = (String) fClipboard.getContents(textTransfer);
|
||||
pasteString(strText);
|
||||
// TODO paste in another thread.... to avoid blocking
|
||||
// new Thread() {
|
||||
// public void run() {
|
||||
// for (int i = 0; i < strText.length(); i++) {
|
||||
// sendChar(strText.charAt(i), false);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
// }.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param strText
|
||||
*/
|
||||
public boolean pasteString(String strText) {
|
||||
if(!isConnected())
|
||||
return false;
|
||||
if (strText == null)
|
||||
return false;
|
||||
for (int i = 0; i < strText.length(); i++) {
|
||||
sendChar(strText.charAt(i), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#selectAll()
|
||||
*/
|
||||
public void selectAll() {
|
||||
getCtlText().selectAll();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#sendKey(char)
|
||||
*/
|
||||
public void sendKey(char character) {
|
||||
Event event;
|
||||
KeyEvent keyEvent;
|
||||
|
||||
event = new Event();
|
||||
event.widget = getCtlText();
|
||||
event.character = character;
|
||||
event.keyCode = 0;
|
||||
event.stateMask = 0;
|
||||
event.doit = true;
|
||||
keyEvent = new KeyEvent(event);
|
||||
|
||||
fKeyHandler.keyPressed(keyEvent);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#clearTerminal()
|
||||
*/
|
||||
public void clearTerminal() {
|
||||
// The TerminalText object does all text manipulation.
|
||||
|
||||
getTerminalText().clearTerminal();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getClipboard()
|
||||
*/
|
||||
public Clipboard getClipboard() {
|
||||
return fClipboard;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return non null selection
|
||||
*/
|
||||
public String getSelection() {
|
||||
String txt= fCtlText.getSelectionText();
|
||||
if(txt==null)
|
||||
txt=""; //$NON-NLS-1$
|
||||
return txt;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setFocus()
|
||||
*/
|
||||
public void setFocus() {
|
||||
getCtlText().setFocus();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isEmpty()
|
||||
*/
|
||||
public boolean isEmpty() {
|
||||
return getCtlText().isEmpty();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isDisposed()
|
||||
*/
|
||||
public boolean isDisposed() {
|
||||
return getCtlText().isDisposed();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isConnected()
|
||||
*/
|
||||
public boolean isConnected() {
|
||||
return fState==TerminalState.CONNECTED;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#disposeTerminal()
|
||||
*/
|
||||
public void disposeTerminal() {
|
||||
Logger.log("entered."); //$NON-NLS-1$
|
||||
disconnectTerminal();
|
||||
fClipboard.dispose();
|
||||
getTerminalText().dispose();
|
||||
}
|
||||
|
||||
public void connectTerminal() {
|
||||
Logger.log("entered."); //$NON-NLS-1$
|
||||
if(getTerminalConnector()==null)
|
||||
return;
|
||||
fTerminalText.resetState();
|
||||
if(fConnectorInfo.getInitializationErrorMessage()!=null) {
|
||||
showErrorMessage(NLS.bind(
|
||||
TerminalMessages.CannotConnectTo,
|
||||
fConnectorInfo.getName(),
|
||||
fConnectorInfo.getInitializationErrorMessage()));
|
||||
// we cannot connect because the connector was not initialized
|
||||
return;
|
||||
}
|
||||
getTerminalConnector().connect(this);
|
||||
// clean the error message
|
||||
setMsg(""); //$NON-NLS-1$
|
||||
waitForConnect();
|
||||
}
|
||||
|
||||
private ITerminalConnector getTerminalConnector() {
|
||||
if(fConnectorInfo==null)
|
||||
return null;
|
||||
return fConnectorInfo.getConnector();
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#disconnectTerminal()
|
||||
*/
|
||||
public void disconnectTerminal() {
|
||||
Logger.log("entered."); //$NON-NLS-1$
|
||||
|
||||
if (getState()==TerminalState.CLOSED) {
|
||||
return;
|
||||
}
|
||||
if(getTerminalConnector()!=null) {
|
||||
getTerminalConnector().disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
// TODO
|
||||
private void waitForConnect() {
|
||||
Logger.log("entered."); //$NON-NLS-1$
|
||||
// TODO
|
||||
// Eliminate this code
|
||||
while (getState()==TerminalState.CONNECTING) {
|
||||
if (fDisplay.readAndDispatch())
|
||||
continue;
|
||||
|
||||
fDisplay.sleep();
|
||||
}
|
||||
if (!getMsg().equals("")) //$NON-NLS-1$
|
||||
{
|
||||
showErrorMessage(getMsg());
|
||||
|
||||
disconnectTerminal();
|
||||
return;
|
||||
}
|
||||
getCtlText().setFocus();
|
||||
startReaderJob();
|
||||
|
||||
}
|
||||
|
||||
private void startReaderJob() {
|
||||
if(fJob==null) {
|
||||
fJob=new Job("Terminal data reader") { //$NON-NLS-1$
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
IStatus status=Status.OK_STATUS;
|
||||
while(true) {
|
||||
while(fInputStream.available()==0 && !monitor.isCanceled()) {
|
||||
try {
|
||||
fInputStream.waitForAvailable(500);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
if(monitor.isCanceled()) {
|
||||
disconnectTerminal();
|
||||
status=Status.CANCEL_STATUS;
|
||||
break;
|
||||
}
|
||||
try {
|
||||
// TODO: should block when no text is available!
|
||||
fTerminalText.processText();
|
||||
|
||||
} catch (Exception e) {
|
||||
disconnectTerminal();
|
||||
status=new Status(IStatus.ERROR,TerminalPlugin.PLUGIN_ID,e.getLocalizedMessage(),e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// clean the job: start a new one when the connection getst restarted
|
||||
fJob=null;
|
||||
return status;
|
||||
}
|
||||
|
||||
};
|
||||
fJob.setSystem(true);
|
||||
fJob.schedule();
|
||||
}
|
||||
}
|
||||
|
||||
private void showErrorMessage(String message) {
|
||||
String strTitle = TerminalMessages.TerminalError;
|
||||
MessageDialog.openError( getShell(), strTitle, message);
|
||||
}
|
||||
|
||||
protected void sendString(String string) {
|
||||
try {
|
||||
// Send the string after converting it to an array of bytes using the
|
||||
// platform's default character encoding.
|
||||
//
|
||||
// TODO: Find a way to force this to use the ISO Latin-1 encoding.
|
||||
|
||||
getOutputStream().write(string.getBytes());
|
||||
getOutputStream().flush();
|
||||
} catch (SocketException socketException) {
|
||||
displayTextInTerminal(socketException.getMessage());
|
||||
|
||||
String strMsg = TerminalMessages.SocketError
|
||||
+ "!\n" + socketException.getMessage(); //$NON-NLS-1$
|
||||
showErrorMessage(strMsg);
|
||||
|
||||
Logger.logException(socketException);
|
||||
|
||||
disconnectTerminal();
|
||||
} catch (IOException ioException) {
|
||||
showErrorMessage(TerminalMessages.IOError + "!\n" + ioException.getMessage());//$NON-NLS-1$
|
||||
|
||||
Logger.logException(ioException);
|
||||
|
||||
disconnectTerminal();
|
||||
}
|
||||
}
|
||||
|
||||
public Shell getShell() {
|
||||
return getCtlText().getShell();
|
||||
}
|
||||
|
||||
protected void sendChar(char chKey, boolean altKeyPressed) {
|
||||
try {
|
||||
int byteToSend = chKey;
|
||||
|
||||
if (altKeyPressed) {
|
||||
// When the ALT key is pressed at the same time that a character is
|
||||
// typed, translate it into an ESCAPE followed by the character. The
|
||||
// alternative in this case is to set the high bit of the character
|
||||
// being transmitted, but that will cause input such as ALT-f to be
|
||||
// seen as the ISO Latin-1 character '�', which can be confusing to
|
||||
// European users running Emacs, for whom Alt-f should move forward a
|
||||
// word instead of inserting the '�' character.
|
||||
//
|
||||
// TODO: Make the ESCAPE-vs-highbit behavior user configurable.
|
||||
|
||||
Logger.log("sending ESC + '" + byteToSend + "'"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
getOutputStream().write('\u001b');
|
||||
getOutputStream().write(byteToSend);
|
||||
} else {
|
||||
Logger.log("sending '" + byteToSend + "'"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
getOutputStream().write(byteToSend);
|
||||
}
|
||||
|
||||
getOutputStream().flush();
|
||||
} catch (SocketException socketException) {
|
||||
Logger.logException(socketException);
|
||||
|
||||
displayTextInTerminal(socketException.getMessage());
|
||||
|
||||
String strMsg = TerminalMessages.SocketError
|
||||
+ "!\n" + socketException.getMessage(); //$NON-NLS-1$
|
||||
|
||||
showErrorMessage(strMsg);
|
||||
Logger.logException(socketException);
|
||||
|
||||
disconnectTerminal();
|
||||
} catch (IOException ioException) {
|
||||
Logger.logException(ioException);
|
||||
|
||||
displayTextInTerminal(ioException.getMessage());
|
||||
|
||||
String strMsg = TerminalMessages.IOError + "!\n" + ioException.getMessage(); //$NON-NLS-1$
|
||||
|
||||
showErrorMessage(strMsg);
|
||||
Logger.logException(ioException);
|
||||
|
||||
disconnectTerminal();
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setupTerminal()
|
||||
*/
|
||||
public void setupTerminal(Composite parent) {
|
||||
fState=TerminalState.CLOSED;
|
||||
setupControls(parent);
|
||||
setupListeners();
|
||||
setupHelp(fWndParent, TerminalPlugin.HELP_VIEW);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#onFontChanged()
|
||||
*/
|
||||
public void setFont(Font font) {
|
||||
getCtlText().setFont(font);
|
||||
if(fCommandInputField!=null) {
|
||||
fCommandInputField.setFont(font);
|
||||
}
|
||||
|
||||
// Tell the TerminalControl singleton that the font has changed.
|
||||
|
||||
getTerminalText().fontChanged();
|
||||
}
|
||||
public Font getFont() {
|
||||
return getCtlText().getFont();
|
||||
}
|
||||
public Control getControl() {
|
||||
return fCtlText;
|
||||
}
|
||||
protected void setupControls(Composite parent) {
|
||||
// The Terminal view now aims to be an ANSI-conforming terminal emulator, so it
|
||||
// can't have a horizontal scroll bar (but a vertical one is ok). Also, do
|
||||
// _not_ make the TextViewer read-only, because that prevents it from seeing a
|
||||
// TAB character when the user presses TAB (instead, the TAB causes focus to
|
||||
// switch to another Workbench control). We prevent local keyboard input from
|
||||
// modifying the text in method TerminalVerifyKeyListener.verifyKey().
|
||||
|
||||
fWndParent=new Composite(parent,SWT.NONE);
|
||||
GridLayout layout=new GridLayout();
|
||||
layout.marginWidth=0;
|
||||
layout.marginHeight=0;
|
||||
|
||||
fWndParent.setLayout(layout);
|
||||
|
||||
ITerminalTextDataSnapshot snapshot=fTerminalModel.makeSnapshot();
|
||||
// TODO how to get the initial size correctly!
|
||||
snapshot.updateSnapshot(false);
|
||||
ITextCanvasModel canvasModel=new PollingTextCanvasModel(snapshot);
|
||||
fCtlText=new TextCanvas(fWndParent,canvasModel,SWT.NONE);
|
||||
fCtlText.setCellRenderer(new TextLineRenderer(fCtlText,canvasModel));
|
||||
|
||||
fCtlText.setLayoutData(new GridData(GridData.FILL_BOTH));
|
||||
fCtlText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
|
||||
fCtlText.addListener(SWT.Resize, new Listener() {
|
||||
public void handleEvent(Event e) {
|
||||
Rectangle bonds=fCtlText.getClientArea();
|
||||
int lines=bonds.height/fCtlText.getCellHeight();
|
||||
int columns=bonds.width/fCtlText.getCellWidth();
|
||||
fTerminalText.setDimensions(lines, columns);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
fDisplay = getCtlText().getDisplay();
|
||||
fClipboard = new Clipboard(fDisplay);
|
||||
// fViewer.setDocument(new TerminalDocument());
|
||||
setFont(JFaceResources.getTextFont());
|
||||
}
|
||||
|
||||
protected void setupListeners() {
|
||||
fKeyHandler = new TerminalKeyHandler();
|
||||
fFocusListener = new TerminalFocusListener();
|
||||
|
||||
getCtlText().addKeyListener(fKeyHandler);
|
||||
getCtlText().addFocusListener(fFocusListener);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup all the help contexts for the controls.
|
||||
*/
|
||||
protected void setupHelp(Composite parent, String id) {
|
||||
Control[] children = parent.getChildren();
|
||||
|
||||
for (int nIndex = 0; nIndex < children.length; nIndex++) {
|
||||
if (children[nIndex] instanceof Composite) {
|
||||
setupHelp((Composite) children[nIndex], id);
|
||||
}
|
||||
}
|
||||
|
||||
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, id);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#displayTextInTerminal(java.lang.String)
|
||||
*/
|
||||
public void displayTextInTerminal(String text) {
|
||||
writeToTerminal("\r\n"+text+"\r\n"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
}
|
||||
private void writeToTerminal(String text) {
|
||||
try {
|
||||
getRemoteToTerminalOutputStream().write(text.getBytes("ISO-8859-1")); //$NON-NLS-1$
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
// should never happen!
|
||||
e.printStackTrace();
|
||||
} catch (IOException e) {
|
||||
// should never happen!
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public OutputStream getRemoteToTerminalOutputStream() {
|
||||
return fInputStream.getOutputStream();
|
||||
}
|
||||
protected boolean isLogCharEnabled() {
|
||||
return TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_CHAR);
|
||||
}
|
||||
protected boolean isLogBufferSizeEnabled() {
|
||||
return TerminalPlugin
|
||||
.isOptionEnabled(Logger.TRACE_DEBUG_LOG_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
|
||||
public OutputStream getOutputStream() {
|
||||
if(getTerminalConnector()!=null)
|
||||
return getTerminalConnector().getOutputStream();
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setMsg(java.lang.String)
|
||||
*/
|
||||
public void setMsg(String msg) {
|
||||
fMsg = msg;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return fMsg;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getCtlText()
|
||||
*/
|
||||
protected TextCanvas getCtlText() {
|
||||
return fCtlText;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getTerminalText()
|
||||
*/
|
||||
public VT100Emulator getTerminalText() {
|
||||
return fTerminalText;
|
||||
}
|
||||
|
||||
/**
|
||||
*/
|
||||
public ITerminalConnectorInfo getTerminalConnectorInfo() {
|
||||
return fConnectorInfo;
|
||||
}
|
||||
|
||||
protected class TerminalFocusListener implements FocusListener {
|
||||
private IContextActivation contextActivation = null;
|
||||
|
||||
protected TerminalFocusListener() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void focusGained(FocusEvent event) {
|
||||
// Disable all keyboard accelerators (e.g., Control-B) so the Terminal view
|
||||
// can see every keystroke. Without this, Emacs, vi, and Bash are unusable
|
||||
// in the Terminal view.
|
||||
|
||||
IBindingService bindingService = (IBindingService) PlatformUI
|
||||
.getWorkbench().getAdapter(IBindingService.class);
|
||||
bindingService.setKeyFilterEnabled(false);
|
||||
|
||||
// The above code fails to cause Eclipse to disable menu-activation
|
||||
// accelerators (e.g., Alt-F for the File menu), so we set the command
|
||||
// context to be the Terminal view's command context. This enables us to
|
||||
// override menu-activation accelerators with no-op commands in our
|
||||
// plugin.xml file, which enables the Terminal view to see absolutly _all_
|
||||
// key-presses.
|
||||
|
||||
IContextService contextService = (IContextService) PlatformUI
|
||||
.getWorkbench().getAdapter(IContextService.class);
|
||||
contextActivation = contextService
|
||||
.activateContext("org.eclipse.tm.terminal.TerminalContext"); //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public void focusLost(FocusEvent event) {
|
||||
// Enable all keybindings.
|
||||
|
||||
IBindingService bindingService = (IBindingService) PlatformUI
|
||||
.getWorkbench().getAdapter(IBindingService.class);
|
||||
bindingService.setKeyFilterEnabled(true);
|
||||
|
||||
// Restore the command context to its previous value.
|
||||
|
||||
IContextService contextService = (IContextService) PlatformUI
|
||||
.getWorkbench().getAdapter(IContextService.class);
|
||||
contextService.deactivateContext(contextActivation);
|
||||
}
|
||||
}
|
||||
|
||||
protected class TerminalKeyHandler extends KeyAdapter {
|
||||
public void keyPressed(KeyEvent event) {
|
||||
if (getState()==TerminalState.CONNECTING)
|
||||
return;
|
||||
|
||||
// We set the event.doit to false to prevent any further processing of this
|
||||
// key event. The only reason this is here is because I was seeing the F10
|
||||
// key both send an escape sequence (due to this method) and switch focus
|
||||
// to the Workbench File menu (forcing the user to click in the Terminal
|
||||
// view again to continue entering text). This fixes that.
|
||||
|
||||
event.doit = false;
|
||||
|
||||
char character = event.character;
|
||||
|
||||
if (!isConnected()) {
|
||||
// Pressing ENTER while not connected causes us to connect.
|
||||
if (character == '\r') {
|
||||
connectTerminal();
|
||||
return;
|
||||
}
|
||||
|
||||
// Ignore all other keyboard input when not connected.
|
||||
return;
|
||||
}
|
||||
|
||||
// If the event character is NUL ('\u0000'), then a special key was pressed
|
||||
// (e.g., PageUp, PageDown, an arrow key, a function key, Shift, Alt,
|
||||
// Control, etc.). The one exception is when the user presses Control-@,
|
||||
// which sends a NUL character, in which case we must send the NUL to the
|
||||
// remote endpoint. This is necessary so that Emacs will work correctly,
|
||||
// because Control-@ (i.e., NUL) invokes Emacs' set-mark-command when Emacs
|
||||
// is running on a terminal. When the user presses Control-@, the keyCode
|
||||
// is 50.
|
||||
|
||||
if (character == '\u0000' && event.keyCode != 50) {
|
||||
// A special key was pressed. Figure out which one it was and send the
|
||||
// appropriate ANSI escape sequence.
|
||||
//
|
||||
// IMPORTANT: Control will not enter this method for these special keys
|
||||
// unless certain <keybinding> tags are present in the plugin.xml file
|
||||
// for the Terminal view. Do not delete those tags.
|
||||
|
||||
switch (event.keyCode) {
|
||||
case 0x1000001: // Up arrow.
|
||||
sendString("\u001b[A"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000002: // Down arrow.
|
||||
sendString("\u001b[B"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000003: // Left arrow.
|
||||
sendString("\u001b[D"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000004: // Right arrow.
|
||||
sendString("\u001b[C"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000005: // PgUp key.
|
||||
sendString("\u001b[I"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000006: // PgDn key.
|
||||
sendString("\u001b[G"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000007: // Home key.
|
||||
sendString("\u001b[H"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000008: // End key.
|
||||
sendString("\u001b[F"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x100000a: // F1 key.
|
||||
sendString("\u001b[M"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x100000b: // F2 key.
|
||||
sendString("\u001b[N"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x100000c: // F3 key.
|
||||
sendString("\u001b[O"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x100000d: // F4 key.
|
||||
sendString("\u001b[P"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x100000e: // F5 key.
|
||||
sendString("\u001b[Q"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x100000f: // F6 key.
|
||||
sendString("\u001b[R"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000010: // F7 key.
|
||||
sendString("\u001b[S"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000011: // F8 key.
|
||||
sendString("\u001b[T"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000012: // F9 key.
|
||||
sendString("\u001b[U"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000013: // F10 key.
|
||||
sendString("\u001b[V"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000014: // F11 key.
|
||||
sendString("\u001b[W"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
case 0x1000015: // F12 key.
|
||||
sendString("\u001b[X"); //$NON-NLS-1$
|
||||
break;
|
||||
|
||||
default:
|
||||
// Ignore other special keys. Control flows through this case when
|
||||
// the user presses SHIFT, CONTROL, ALT, and any other key not
|
||||
// handled by the above cases.
|
||||
break;
|
||||
}
|
||||
|
||||
// It's ok to return here, because we never locally echo special keys.
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// To fix SPR 110341, we consider the Alt key to be pressed only when the
|
||||
// Control key is _not_ also pressed. This works around a bug in SWT where,
|
||||
// on European keyboards, the AltGr key being pressed appears to us as Control
|
||||
// + Alt being pressed simultaneously.
|
||||
|
||||
Logger.log("stateMask = " + event.stateMask); //$NON-NLS-1$
|
||||
|
||||
boolean altKeyPressed = (((event.stateMask & SWT.ALT) != 0) && ((event.stateMask & SWT.CTRL) == 0));
|
||||
|
||||
if (!altKeyPressed && (event.stateMask & SWT.CTRL) != 0
|
||||
&& character == ' ') {
|
||||
// Send a NUL character -- many terminal emulators send NUL when
|
||||
// Control-Space is pressed. This is used to set the mark in Emacs.
|
||||
|
||||
character = '\u0000';
|
||||
}
|
||||
|
||||
sendChar(character, altKeyPressed);
|
||||
|
||||
// Special case: When we are in a TCP connection and echoing characters
|
||||
// locally, send a LF after sending a CR.
|
||||
// ISSUE: Is this absolutely required?
|
||||
|
||||
if (character == '\r' && getTerminalConnectorInfo() != null
|
||||
&& isConnected()
|
||||
&& getTerminalConnectorInfo().getConnector().isLocalEcho()) {
|
||||
sendChar('\n', false);
|
||||
}
|
||||
|
||||
// Now decide if we should locally echo the character we just sent. We do
|
||||
// _not_ locally echo the character if any of these conditions are true:
|
||||
//
|
||||
// o This is a serial connection.
|
||||
//
|
||||
// o This is a TCP connection (i.e., m_telnetConnection is not null) and
|
||||
// the remote endpoint is not a TELNET server.
|
||||
//
|
||||
// o The ALT (or META) key is pressed.
|
||||
//
|
||||
// o The character is any of the first 32 ISO Latin-1 characters except
|
||||
// Control-I or Control-M.
|
||||
//
|
||||
// o The character is the DELETE character.
|
||||
|
||||
if (getTerminalConnectorInfo() == null
|
||||
|| getTerminalConnectorInfo().getConnector().isLocalEcho() == false || altKeyPressed
|
||||
|| (character >= '\u0001' && character < '\t')
|
||||
|| (character > '\t' && character < '\r')
|
||||
|| (character > '\r' && character <= '\u001f')
|
||||
|| character == '\u007f') {
|
||||
// No local echoing.
|
||||
return;
|
||||
}
|
||||
|
||||
// Locally echo the character.
|
||||
|
||||
StringBuffer charBuffer = new StringBuffer();
|
||||
charBuffer.append(character);
|
||||
|
||||
// If the character is a carriage return, we locally echo it as a CR + LF
|
||||
// combination.
|
||||
|
||||
if (character == '\r')
|
||||
charBuffer.append('\n');
|
||||
|
||||
writeToTerminal(charBuffer.toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void setTerminalTitle(String title) {
|
||||
fTerminalListener.setTerminalTitle(title);
|
||||
}
|
||||
|
||||
|
||||
public TerminalState getState() {
|
||||
return fState;
|
||||
}
|
||||
|
||||
|
||||
public void setState(TerminalState state) {
|
||||
fState=state;
|
||||
fTerminalListener.setState(state);
|
||||
}
|
||||
|
||||
public String getSettingsSummary() {
|
||||
if(getTerminalConnector()!=null)
|
||||
return getTerminalConnector().getSettingsSummary();
|
||||
return ""; //$NON-NLS-1$
|
||||
}
|
||||
|
||||
public void setConnector(ITerminalConnectorInfo connector) {
|
||||
fConnectorInfo=connector;
|
||||
|
||||
}
|
||||
public ICommandInputField getCommandInputField() {
|
||||
return fCommandInputField;
|
||||
}
|
||||
|
||||
public void setCommandInputField(ICommandInputField inputField) {
|
||||
if(fCommandInputField!=null)
|
||||
fCommandInputField.dispose();
|
||||
fCommandInputField=inputField;
|
||||
if(fCommandInputField!=null)
|
||||
fCommandInputField.createControl(fWndParent, this);
|
||||
fWndParent.layout(true);
|
||||
}
|
||||
|
||||
public int getBufferLineLimit() {
|
||||
return fTerminalModel.getMaxHeight();
|
||||
}
|
||||
|
||||
public void setBufferLineLimit(int bufferLineLimit) {
|
||||
if(bufferLineLimit<=0)
|
||||
return;
|
||||
synchronized (fTerminalModel) {
|
||||
if(fTerminalModel.getHeight()>bufferLineLimit)
|
||||
fTerminalModel.setDimensions(bufferLineLimit, fTerminalModel.getWidth());
|
||||
fTerminalModel.setMaxHeight(bufferLineLimit);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
|
||||
public interface ISnapshotChanges {
|
||||
|
||||
/**
|
||||
* @param line might bigger than the number of lines....
|
||||
*/
|
||||
void markLineChanged(int line);
|
||||
|
||||
/**
|
||||
* Marks all lines in the range as changed
|
||||
* @param line >=0
|
||||
* @param n might be out of range
|
||||
*/
|
||||
void markLinesChanged(int line, int n);
|
||||
|
||||
/**
|
||||
* Marks all lines within the scrolling region
|
||||
* changed and resets the scrolling information
|
||||
*/
|
||||
void convertScrollingIntoChanges();
|
||||
|
||||
/**
|
||||
* @return true if something has changed
|
||||
*/
|
||||
boolean hasChanged();
|
||||
|
||||
/**
|
||||
* @param startLine
|
||||
* @param size
|
||||
* @param shift
|
||||
*/
|
||||
void scroll(int startLine, int size, int shift);
|
||||
|
||||
/**
|
||||
* Mark all lines changed
|
||||
* @param height if no window is set this is the number of
|
||||
* lines that are marked as changed
|
||||
*/
|
||||
void setAllChanged(int height);
|
||||
|
||||
int getFirstChangedLine();
|
||||
|
||||
int getLastChangedLine();
|
||||
|
||||
int getScrollWindowStartLine();
|
||||
|
||||
int getScrollWindowSize();
|
||||
|
||||
int getScrollWindowShift();
|
||||
|
||||
boolean hasLineChanged(int line);
|
||||
|
||||
void markDimensionsChanged();
|
||||
boolean hasDimensionsChanged();
|
||||
void markCursorChanged();
|
||||
|
||||
/**
|
||||
* @return true if the terminal data has changed
|
||||
*/
|
||||
boolean hasTerminalChanged();
|
||||
/**
|
||||
* mark the terminal as changed
|
||||
*/
|
||||
void setTerminalChanged();
|
||||
|
||||
|
||||
void copyChangedLines(ITerminalTextData dest, ITerminalTextData source);
|
||||
|
||||
/**
|
||||
* @param startLine -1 means follow the end of the data
|
||||
* @param size number of lines to follow
|
||||
*/
|
||||
void setInterestWindow(int startLine, int size);
|
||||
int getInterestWindowStartLine();
|
||||
int getInterestWindowSize();
|
||||
|
||||
}
|
|
@ -0,0 +1,381 @@
|
|||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
|
||||
|
||||
/**
|
||||
* Collects the changes of the {@link ITerminalTextData}
|
||||
*
|
||||
*/
|
||||
public class SnapshotChanges implements ISnapshotChanges {
|
||||
/**
|
||||
* The first line changed
|
||||
*/
|
||||
private int fFirstChangedLine;
|
||||
/**
|
||||
* The last line changed
|
||||
*/
|
||||
private int fLastChangedLine;
|
||||
private int fScrollWindowStartLine;
|
||||
private int fScrollWindowSize;
|
||||
private int fScrollWindowShift;
|
||||
/**
|
||||
* true, if scrolling should not tracked anymore
|
||||
*/
|
||||
private boolean fScrollDontTrack;
|
||||
/**
|
||||
* The lines that need to be copied
|
||||
* into the snapshot (lines that have
|
||||
* not changed don't have to be copied)
|
||||
*/
|
||||
private boolean[] fChangedLines;
|
||||
|
||||
private int fInterestWindowSize;
|
||||
private int fInterestWindowStartLine;
|
||||
private boolean fDimensionsChanged;
|
||||
private boolean fTerminalHasChanged;
|
||||
private boolean fCursorHasChanged;
|
||||
|
||||
public SnapshotChanges(int nLines) {
|
||||
setChangedLinesLength(nLines);
|
||||
fFirstChangedLine=Integer.MAX_VALUE;
|
||||
fLastChangedLine=-1;
|
||||
}
|
||||
public SnapshotChanges(int windowStart, int windowSize) {
|
||||
setChangedLinesLength(windowStart+windowSize);
|
||||
fFirstChangedLine=Integer.MAX_VALUE;
|
||||
fLastChangedLine=-1;
|
||||
fInterestWindowStartLine=windowStart;
|
||||
fInterestWindowSize=windowSize;
|
||||
|
||||
}
|
||||
/**
|
||||
* This is used in asserts to throw an {@link RuntimeException}.
|
||||
* This is useful for tests.
|
||||
* @return never -- throws an exception
|
||||
*/
|
||||
private boolean throwRuntimeException() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
/**
|
||||
* @param line
|
||||
* @param size
|
||||
* @return true if the range overlaps with the interest window
|
||||
*/
|
||||
boolean isInInterestWindow(int line, int size) {
|
||||
if(fInterestWindowSize<=0)
|
||||
return true;
|
||||
if(line+size<=fInterestWindowStartLine || line>=fInterestWindowStartLine+fInterestWindowSize)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @param line
|
||||
* @return true if the line is within the interest window
|
||||
*/
|
||||
boolean isInInterestWindow(int line) {
|
||||
if(fInterestWindowSize<=0)
|
||||
return true;
|
||||
if(line<fInterestWindowStartLine || line>=fInterestWindowStartLine+fInterestWindowSize)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @param line
|
||||
* @return the line within the window
|
||||
*/
|
||||
int fitLineToWindow(int line) {
|
||||
if(fInterestWindowSize<=0)
|
||||
return line;
|
||||
if(line<fInterestWindowStartLine)
|
||||
return fInterestWindowStartLine;
|
||||
return line;
|
||||
}
|
||||
/**
|
||||
* The result is only defined if {@link #isInInterestWindow(int, int)} returns true!
|
||||
* @param line the line <b>before</b> {@link #fitLineToWindow(int)} has been called!
|
||||
* @param size
|
||||
* @return the adjusted size.
|
||||
* <p>Note:</p> {@link #fitLineToWindow(int)} has to be called on the line to
|
||||
* move the window correctly!
|
||||
*/
|
||||
int fitSizeToWindow(int line, int size) {
|
||||
if(fInterestWindowSize<=0)
|
||||
return size;
|
||||
if(line<fInterestWindowStartLine) {
|
||||
size-=fInterestWindowStartLine-line;
|
||||
line=fInterestWindowStartLine;
|
||||
}
|
||||
if(line+size>fInterestWindowStartLine+fInterestWindowSize)
|
||||
size=fInterestWindowStartLine+fInterestWindowSize-line;
|
||||
return size;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#markLineChanged(int)
|
||||
*/
|
||||
public void markLineChanged(int line) {
|
||||
if(!isInInterestWindow(line))
|
||||
return;
|
||||
line=fitLineToWindow(line);
|
||||
if(line<fFirstChangedLine)
|
||||
fFirstChangedLine=line;
|
||||
if(line>fLastChangedLine)
|
||||
fLastChangedLine=line;
|
||||
// in case the terminal got resized we expand
|
||||
// don't remember the changed line because
|
||||
// there is nothing to copy
|
||||
if(line<getChangedLineLength()) {
|
||||
setChangedLine(line,true);
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#markLinesChanged(int, int)
|
||||
*/
|
||||
public void markLinesChanged(int line, int n) {
|
||||
if(n<=0 || !isInInterestWindow(line,n))
|
||||
return;
|
||||
// do not exceed the bounds of fChangedLines
|
||||
// the terminal might have been resized and
|
||||
// we can only keep changes for the size of the
|
||||
// previous terminal
|
||||
n=fitSizeToWindow(line, n);
|
||||
line=fitLineToWindow(line);
|
||||
int m=Math.min(line+n, getChangedLineLength());
|
||||
for (int i = line; i < m; i++) {
|
||||
setChangedLine(i,true);
|
||||
}
|
||||
// this sets fFirstChangedLine as well
|
||||
markLineChanged(line);
|
||||
// this sets fLastChangedLine as well
|
||||
markLineChanged(line+n-1);
|
||||
}
|
||||
public void markCursorChanged() {
|
||||
fCursorHasChanged=true;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#convertScrollingIntoChanges()
|
||||
*/
|
||||
public void convertScrollingIntoChanges() {
|
||||
markLinesChanged(fScrollWindowStartLine,fScrollWindowSize);
|
||||
fScrollWindowStartLine=0;
|
||||
fScrollWindowSize=0;
|
||||
fScrollWindowShift=0;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#hasChanged()
|
||||
*/
|
||||
public boolean hasChanged() {
|
||||
if(fFirstChangedLine!=Integer.MAX_VALUE || fLastChangedLine>0 || fScrollWindowShift!=0 ||fDimensionsChanged || fCursorHasChanged)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
public void markDimensionsChanged() {
|
||||
fDimensionsChanged=true;
|
||||
}
|
||||
public boolean hasDimensionsChanged() {
|
||||
return fDimensionsChanged;
|
||||
}
|
||||
public boolean hasTerminalChanged() {
|
||||
return fTerminalHasChanged;
|
||||
}
|
||||
public void setTerminalChanged() {
|
||||
fTerminalHasChanged=true;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#scroll(int, int, int)
|
||||
*/
|
||||
public void scroll(int startLine, int size, int shift) {
|
||||
size=fitSizeToWindow(startLine, size);
|
||||
startLine=fitLineToWindow(startLine);
|
||||
// let's track only negative shifts
|
||||
if(fScrollDontTrack) {
|
||||
// we are in a state where we cannot track scrolling
|
||||
// so let's simply mark the scrolled lines as changed
|
||||
markLinesChanged(startLine, size);
|
||||
} else if(shift>=0) {
|
||||
// we cannot handle positive scroll
|
||||
// forget about clever caching of scroll events
|
||||
doNotTrackScrollingAnymore();
|
||||
// mark all lines inside the scroll region as changed
|
||||
markLinesChanged(startLine, size);
|
||||
} else {
|
||||
// we have already scrolled
|
||||
if(fScrollWindowShift<0) {
|
||||
// we have already scrolled
|
||||
if(fScrollWindowStartLine==startLine && fScrollWindowSize==size) {
|
||||
// we are scrolling the same region again?
|
||||
fScrollWindowShift+=shift;
|
||||
scrollChangesLinesWithNegativeShift(startLine,size,shift);
|
||||
} else {
|
||||
// mark all lines in the old scroll region as changed
|
||||
doNotTrackScrollingAnymore();
|
||||
// mark all lines changed, because
|
||||
markLinesChanged(startLine, size);
|
||||
}
|
||||
} else {
|
||||
// first scroll in this change -- we just notify it
|
||||
fScrollWindowStartLine=startLine;
|
||||
fScrollWindowSize=size;
|
||||
fScrollWindowShift=shift;
|
||||
scrollChangesLinesWithNegativeShift(startLine,size,shift);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Some incompatible scrolling occurred. We cannot do the
|
||||
* scroll optimization anymore...
|
||||
*/
|
||||
private void doNotTrackScrollingAnymore() {
|
||||
if(fScrollWindowSize>0) {
|
||||
// convert the current scrolling into changes
|
||||
markLinesChanged(fScrollWindowStartLine, fScrollWindowSize);
|
||||
fScrollWindowStartLine=0;
|
||||
fScrollWindowSize=0;
|
||||
fScrollWindowShift=0;
|
||||
}
|
||||
// don't be clever on scrolling anymore
|
||||
fScrollDontTrack=true;
|
||||
}
|
||||
/**
|
||||
* Scrolls the changed lines data
|
||||
*
|
||||
* @param line
|
||||
* @param n
|
||||
* @param shift must be negative!
|
||||
*/
|
||||
private void scrollChangesLinesWithNegativeShift(int line, int n, int shift) {
|
||||
assert shift <0 || throwRuntimeException();
|
||||
// scroll the region
|
||||
// don't run out of bounds!
|
||||
int m=Math.min(line+n+shift,getChangedLineLength()+shift);
|
||||
for (int i = line; i < m; i++) {
|
||||
setChangedLine(i, hasLineChanged(i-shift));
|
||||
// move the first changed line up.
|
||||
// We don't have to move the maximum down,
|
||||
// because with a shift scroll, the max is moved
|
||||
// my the next loop in this method
|
||||
if(i<fFirstChangedLine && hasLineChanged(i)) {
|
||||
fFirstChangedLine=i;
|
||||
}
|
||||
}
|
||||
// mark the "opened" lines as changed
|
||||
for (int i = Math.max(0,line+n+shift); i < line+n; i++) {
|
||||
markLineChanged(i);
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#setAllChanged(int)
|
||||
*/
|
||||
public void setAllChanged(int height) {
|
||||
fScrollWindowStartLine=0;
|
||||
fScrollWindowSize=0;
|
||||
fScrollWindowShift=0;
|
||||
fFirstChangedLine=fitLineToWindow(0);
|
||||
fLastChangedLine=fFirstChangedLine+fitSizeToWindow(0, height)-1;
|
||||
// no need to keep an array of changes anymore
|
||||
setChangedLinesLength(0);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#getFirstChangedLine()
|
||||
*/
|
||||
public int getFirstChangedLine() {
|
||||
return fFirstChangedLine;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#getLastChangedLine()
|
||||
*/
|
||||
public int getLastChangedLine() {
|
||||
return fLastChangedLine;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#getScrollWindowStartLine()
|
||||
*/
|
||||
public int getScrollWindowStartLine() {
|
||||
return fScrollWindowStartLine;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#getScrollWindowSize()
|
||||
*/
|
||||
public int getScrollWindowSize() {
|
||||
return fScrollWindowSize;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#getScrollWindowShift()
|
||||
*/
|
||||
public int getScrollWindowShift() {
|
||||
return fScrollWindowShift;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#copyChangedLines(org.eclipse.tm.terminal.model.ITerminalTextData, org.eclipse.tm.terminal.model.ITerminalTextData)
|
||||
*/
|
||||
public void copyChangedLines(ITerminalTextData dest, ITerminalTextData source) {
|
||||
int n=Math.min(fLastChangedLine+1,source.getHeight());
|
||||
for (int i = fFirstChangedLine; i < n ; i++) {
|
||||
if(hasLineChanged(i))
|
||||
dest.copyLine(source,i,i);
|
||||
}
|
||||
}
|
||||
|
||||
public int getInterestWindowSize() {
|
||||
return fInterestWindowSize;
|
||||
}
|
||||
|
||||
public int getInterestWindowStartLine() {
|
||||
return fInterestWindowStartLine;
|
||||
}
|
||||
|
||||
public void setInterestWindow(int startLine, int size) {
|
||||
int oldStartLine=fInterestWindowStartLine;
|
||||
int oldSize=fInterestWindowSize;
|
||||
fInterestWindowStartLine=startLine;
|
||||
fInterestWindowSize=size;
|
||||
if(oldSize>0) {
|
||||
int shift=oldStartLine-startLine;
|
||||
if(shift==0) {
|
||||
if(size>oldSize) {
|
||||
// add lines to the end
|
||||
markLinesChanged(oldStartLine+oldSize, size-oldSize);
|
||||
}
|
||||
// else no lines within the window have changed
|
||||
|
||||
} else if(Math.abs(shift)<size) {
|
||||
if(shift<0) {
|
||||
// we can scroll
|
||||
scroll(startLine, oldSize, shift);
|
||||
// mark the lines at the end as new
|
||||
for (int i = oldStartLine+oldSize; i < startLine+size; i++) {
|
||||
markLineChanged(i);
|
||||
}
|
||||
} else {
|
||||
// we cannot shift positive -- mark all changed
|
||||
markLinesChanged(startLine, size);
|
||||
}
|
||||
} else {
|
||||
// no scrolling possible
|
||||
markLinesChanged(startLine, size);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#hasLineChanged(int)
|
||||
*/
|
||||
public boolean hasLineChanged(int line) {
|
||||
if(line<fChangedLines.length)
|
||||
return fChangedLines[line];
|
||||
// since the height of the terminal could
|
||||
// have changed but we have tracked only changes
|
||||
// of the previous terminal height, any line outside
|
||||
// the the range of the previous height has changed
|
||||
return isInInterestWindow(line);
|
||||
}
|
||||
int getChangedLineLength() {
|
||||
return fChangedLines.length;
|
||||
}
|
||||
void setChangedLine(int line,boolean changed){
|
||||
fChangedLines[line]=changed;
|
||||
}
|
||||
void setChangedLinesLength(int length) {
|
||||
fChangedLines=new boolean[length];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse synchronized public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
* This is a decorator to make all access to
|
||||
* ITerminalTextData synchronized
|
||||
*
|
||||
*/
|
||||
public class SynchronizedTerminalTextData implements ITerminalTextData {
|
||||
final ITerminalTextData fData;
|
||||
public SynchronizedTerminalTextData(ITerminalTextData data) {
|
||||
fData=data;
|
||||
}
|
||||
synchronized public void addLine() {
|
||||
fData.addLine();
|
||||
}
|
||||
synchronized public void cleanLine(int line) {
|
||||
fData.cleanLine(line);
|
||||
}
|
||||
synchronized public void copy(ITerminalTextData source) {
|
||||
fData.copy(source);
|
||||
}
|
||||
synchronized public void copyLine(ITerminalTextData source, int sourceLine, int destLine) {
|
||||
fData.copyLine(source, sourceLine, destLine);
|
||||
}
|
||||
synchronized public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine, int length) {
|
||||
fData.copyRange(source, sourceStartLine, destStartLine, length);
|
||||
}
|
||||
synchronized public char getChar(int line, int column) {
|
||||
return fData.getChar(line, column);
|
||||
}
|
||||
synchronized public char[] getChars(int line) {
|
||||
return fData.getChars(line);
|
||||
}
|
||||
synchronized public int getCursorColumn() {
|
||||
return fData.getCursorColumn();
|
||||
}
|
||||
synchronized public int getCursorLine() {
|
||||
return fData.getCursorLine();
|
||||
}
|
||||
synchronized public int getHeight() {
|
||||
return fData.getHeight();
|
||||
}
|
||||
synchronized public LineSegment[] getLineSegments(int line, int startCol, int numberOfCols) {
|
||||
return fData.getLineSegments(line, startCol, numberOfCols);
|
||||
}
|
||||
synchronized public int getMaxHeight() {
|
||||
return fData.getMaxHeight();
|
||||
}
|
||||
synchronized public Style getStyle(int line, int column) {
|
||||
return fData.getStyle(line, column);
|
||||
}
|
||||
synchronized public Style[] getStyles(int line) {
|
||||
return fData.getStyles(line);
|
||||
}
|
||||
synchronized public int getWidth() {
|
||||
return fData.getWidth();
|
||||
}
|
||||
synchronized public ITerminalTextDataSnapshot makeSnapshot() {
|
||||
return fData.makeSnapshot();
|
||||
}
|
||||
synchronized public void scroll(int startLine, int size, int shift) {
|
||||
fData.scroll(startLine, size, shift);
|
||||
}
|
||||
synchronized public void setChar(int line, int column, char c, Style style) {
|
||||
fData.setChar(line, column, c, style);
|
||||
}
|
||||
synchronized public void setChars(int line, int column, char[] chars, int start, int len, Style style) {
|
||||
fData.setChars(line, column, chars, start, len, style);
|
||||
}
|
||||
synchronized public void setChars(int line, int column, char[] chars, Style style) {
|
||||
fData.setChars(line, column, chars, style);
|
||||
}
|
||||
synchronized public void setCursorColumn(int column) {
|
||||
fData.setCursorColumn(column);
|
||||
}
|
||||
synchronized public void setCursorLine(int line) {
|
||||
fData.setCursorLine(line);
|
||||
}
|
||||
synchronized public void setDimensions(int height, int width) {
|
||||
fData.setDimensions(height, width);
|
||||
}
|
||||
synchronized public void setMaxHeight(int height) {
|
||||
fData.setMaxHeight(height);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,220 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
* This class is thread safe.
|
||||
*
|
||||
*/
|
||||
public class TerminalTextData implements ITerminalTextData {
|
||||
final ITerminalTextData fData;
|
||||
/**
|
||||
* A list of active snapshots
|
||||
*/
|
||||
public TerminalTextDataSnapshot[] fSnapshots=new TerminalTextDataSnapshot[0];
|
||||
private int fCursorColumn;
|
||||
private int fCursorLine;
|
||||
|
||||
public TerminalTextData() {
|
||||
this(new TerminalTextDataFastScroll());
|
||||
|
||||
// this(new TerminalTextDataStore());
|
||||
}
|
||||
public TerminalTextData(ITerminalTextData data) {
|
||||
fData=data;
|
||||
}
|
||||
public int getWidth() {
|
||||
return fData.getWidth();
|
||||
}
|
||||
public int getHeight() {
|
||||
// no need for an extra variable
|
||||
return fData.getHeight();
|
||||
}
|
||||
public void setDimensions(int height, int width) {
|
||||
int h=getHeight();
|
||||
int w=getWidth();
|
||||
if(w==width && h==height)
|
||||
return;
|
||||
fData.setDimensions(height, width);
|
||||
sendDimensionsChanged(h, w, height, width);
|
||||
}
|
||||
private void sendDimensionsChanged(int oldHeight, int oldWidth, int newHeight, int newWidth) {
|
||||
// determine what has changed
|
||||
if(oldWidth==newWidth) {
|
||||
if(oldHeight<newHeight)
|
||||
sendLinesChangedToSnapshot(oldHeight, newHeight-oldHeight);
|
||||
else
|
||||
sendLinesChangedToSnapshot(newHeight,oldHeight-newHeight);
|
||||
} else {
|
||||
sendLinesChangedToSnapshot(0, oldHeight);
|
||||
}
|
||||
sendDimensionsChanged();
|
||||
}
|
||||
public LineSegment[] getLineSegments(int line, int column, int len) {
|
||||
return fData.getLineSegments(line, column, len);
|
||||
}
|
||||
public char getChar(int line, int column) {
|
||||
return fData.getChar(line, column);
|
||||
}
|
||||
public Style getStyle(int line, int column) {
|
||||
return fData.getStyle(line, column);
|
||||
}
|
||||
public void setChar(int line, int column, char c, Style style) {
|
||||
fData.setChar(line, column, c, style);
|
||||
sendLineChangedToSnapshots(line);
|
||||
}
|
||||
public void setChars(int line, int column, char[] chars, Style style) {
|
||||
fData.setChars(line, column, chars, style);
|
||||
sendLineChangedToSnapshots(line);
|
||||
}
|
||||
public void setChars(int line, int column, char[] chars, int start, int len, Style style) {
|
||||
fData.setChars(line, column, chars, start, len, style);
|
||||
sendLineChangedToSnapshots(line);
|
||||
}
|
||||
public void scroll(int startLine, int size, int shift) {
|
||||
fData.scroll(startLine, size, shift);
|
||||
sendScrolledToSnapshots(startLine, size, shift);
|
||||
}
|
||||
public String toString() {
|
||||
return fData.toString();
|
||||
}
|
||||
private void sendDimensionsChanged() {
|
||||
for (int i = 0; i < fSnapshots.length; i++) {
|
||||
fSnapshots[i].markDimensionsChanged();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param line notifies snapshots that line line has changed
|
||||
*/
|
||||
protected void sendLineChangedToSnapshots(int line) {
|
||||
for (int i = 0; i < fSnapshots.length; i++) {
|
||||
fSnapshots[i].markLineChanged(line);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Notify snapshots that multiple lines have changed
|
||||
* @param line changed line
|
||||
* @param n number of changed lines
|
||||
*/
|
||||
protected void sendLinesChangedToSnapshot(int line,int n) {
|
||||
for (int i = 0; i < fSnapshots.length; i++) {
|
||||
fSnapshots[i].markLinesChanged(line, n);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify snapshot that a region was scrolled
|
||||
* @param startLine
|
||||
* @param size
|
||||
* @param shift
|
||||
*/
|
||||
protected void sendScrolledToSnapshots(int startLine,int size, int shift) {
|
||||
for (int i = 0; i < fSnapshots.length; i++) {
|
||||
fSnapshots[i].scroll(startLine, size, shift);
|
||||
}
|
||||
}
|
||||
protected void sendCursorChanged() {
|
||||
for (int i = 0; i < fSnapshots.length; i++) {
|
||||
fSnapshots[i].markCursorChanged();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Removes the snapshot from the @observer@ list
|
||||
* @param snapshot
|
||||
*/
|
||||
protected void removeSnapshot(TerminalTextDataSnapshot snapshot) {
|
||||
// poor mans approach to modify the array
|
||||
List list=new ArrayList();
|
||||
list.addAll(Arrays.asList(fSnapshots));
|
||||
list.remove(snapshot);
|
||||
fSnapshots=(TerminalTextDataSnapshot[]) list.toArray(new TerminalTextDataSnapshot[list.size()]);
|
||||
}
|
||||
|
||||
public ITerminalTextDataSnapshot makeSnapshot() {
|
||||
// poor mans approach to modify the array
|
||||
TerminalTextDataSnapshot snapshot=new TerminalTextDataSnapshot(this);
|
||||
snapshot.markDimensionsChanged();
|
||||
List list=new ArrayList();
|
||||
list.addAll(Arrays.asList(fSnapshots));
|
||||
list.add(snapshot);
|
||||
fSnapshots=(TerminalTextDataSnapshot[]) list.toArray(new TerminalTextDataSnapshot[list.size()]);
|
||||
return snapshot;
|
||||
}
|
||||
public void addLine() {
|
||||
int oldHeight=getHeight();
|
||||
fData.addLine();
|
||||
// was is an append or a scroll?
|
||||
int newHeight=getHeight();
|
||||
if(newHeight>oldHeight) {
|
||||
//the line was appended
|
||||
sendLinesChangedToSnapshot(oldHeight, 1);
|
||||
int width=getWidth();
|
||||
sendDimensionsChanged(oldHeight, width, newHeight, width);
|
||||
|
||||
} else {
|
||||
// the line was scrolled
|
||||
sendScrolledToSnapshots(0, oldHeight, -1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void copy(ITerminalTextData source) {
|
||||
fData.copy(source);
|
||||
fCursorLine=source.getCursorLine();
|
||||
fCursorColumn=source.getCursorColumn();
|
||||
}
|
||||
|
||||
public void copyLine(ITerminalTextData source, int sourceLine, int destLine) {
|
||||
fData.copyLine(source, sourceLine, destLine);
|
||||
}
|
||||
public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine, int length) {
|
||||
fData.copyRange(source, sourceStartLine, destStartLine, length);
|
||||
}
|
||||
public char[] getChars(int line) {
|
||||
return fData.getChars(line);
|
||||
}
|
||||
public Style[] getStyles(int line) {
|
||||
return fData.getStyles(line);
|
||||
}
|
||||
public int getMaxHeight() {
|
||||
return fData.getMaxHeight();
|
||||
}
|
||||
public void setMaxHeight(int height) {
|
||||
fData.setMaxHeight(height);
|
||||
}
|
||||
public void cleanLine(int line) {
|
||||
fData.cleanLine(line);
|
||||
sendLineChangedToSnapshots(line);
|
||||
}
|
||||
public int getCursorColumn() {
|
||||
return fCursorColumn;
|
||||
}
|
||||
public int getCursorLine() {
|
||||
return fCursorLine;
|
||||
}
|
||||
public void setCursorColumn(int column) {
|
||||
fCursorColumn=column;
|
||||
sendCursorChanged();
|
||||
}
|
||||
public void setCursorLine(int line) {
|
||||
fCursorLine=line;
|
||||
sendCursorChanged();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,250 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
* This class is optimized for scrolling the entire {@link #getHeight()}.
|
||||
* The scrolling is done by moving an offset into the data and using
|
||||
* the modulo operator.
|
||||
*
|
||||
*/
|
||||
public class TerminalTextDataFastScroll implements ITerminalTextData {
|
||||
|
||||
final ITerminalTextData fData;
|
||||
private int fHeight;
|
||||
private int fMaxHeight;
|
||||
/**
|
||||
* The offset into the array.
|
||||
*/
|
||||
int fOffset;
|
||||
public TerminalTextDataFastScroll(ITerminalTextData data,int maxHeight) {
|
||||
fMaxHeight=maxHeight;
|
||||
fData=data;
|
||||
fData.setDimensions(maxHeight, fData.getWidth());
|
||||
if(maxHeight>2)
|
||||
assert shiftOffset(-2) || throwRuntimeException();
|
||||
}
|
||||
public TerminalTextDataFastScroll(int maxHeight) {
|
||||
this(new TerminalTextDataStore(),maxHeight);
|
||||
}
|
||||
public TerminalTextDataFastScroll() {
|
||||
this(new TerminalTextDataStore(),1);
|
||||
}
|
||||
/**
|
||||
* This is used in asserts to throw an {@link RuntimeException}.
|
||||
* This is useful for tests.
|
||||
* @return never -- throws an exception
|
||||
*/
|
||||
private boolean throwRuntimeException() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param line
|
||||
* @return the actual line number in {@link #fData}
|
||||
*/
|
||||
int getPositionOfLine(int line) {
|
||||
return (line+fOffset)%fMaxHeight;
|
||||
}
|
||||
/**
|
||||
* Moves offset by delta. This does <b>not</b> move the data!
|
||||
* @param delta
|
||||
*/
|
||||
void moveOffset(int delta) {
|
||||
assert Math.abs(delta)<fMaxHeight || throwRuntimeException();
|
||||
fOffset=(fMaxHeight+fOffset+delta)%fMaxHeight;
|
||||
|
||||
}
|
||||
/**
|
||||
* Test method to shift the offset for testing (if assert ==true)
|
||||
* @param shift TODO
|
||||
* @return true
|
||||
*/
|
||||
private boolean shiftOffset(int shift) {
|
||||
moveOffset(shift);
|
||||
return true;
|
||||
}
|
||||
public void addLine() {
|
||||
if(getHeight()<fMaxHeight) {
|
||||
setDimensions(getHeight()+1, getWidth());
|
||||
} else {
|
||||
scroll(0,getHeight(),-1);
|
||||
}
|
||||
}
|
||||
public void cleanLine(int line) {
|
||||
fData.cleanLine(getPositionOfLine(line));
|
||||
}
|
||||
|
||||
public void copy(ITerminalTextData source) {
|
||||
int n=source.getHeight();
|
||||
setDimensions(source.getHeight(),source.getWidth());
|
||||
for (int i = 0; i < n; i++) {
|
||||
fData.copyLine(source, i, getPositionOfLine(i));
|
||||
}
|
||||
}
|
||||
|
||||
public void copyLine(ITerminalTextData source, int sourceLine, int destLine) {
|
||||
fData.copyLine(source, sourceLine, getPositionOfLine(destLine));
|
||||
}
|
||||
|
||||
public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine, int length) {
|
||||
assert (destStartLine>=0 && destStartLine+length<=fHeight) || throwRuntimeException();
|
||||
for (int i = 0; i < length; i++) {
|
||||
fData.copyLine(source, i+sourceStartLine, getPositionOfLine(i+destStartLine));
|
||||
}
|
||||
}
|
||||
|
||||
public char getChar(int line, int column) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
return fData.getChar(getPositionOfLine(line), column);
|
||||
}
|
||||
|
||||
public char[] getChars(int line) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
return fData.getChars(getPositionOfLine(line));
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return fHeight;
|
||||
}
|
||||
|
||||
public LineSegment[] getLineSegments(int line, int startCol, int numberOfCols) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
return fData.getLineSegments(getPositionOfLine(line), startCol, numberOfCols);
|
||||
}
|
||||
|
||||
public int getMaxHeight() {
|
||||
return fMaxHeight;
|
||||
}
|
||||
|
||||
public Style getStyle(int line, int column) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
return fData.getStyle(getPositionOfLine(line), column);
|
||||
}
|
||||
|
||||
public Style[] getStyles(int line) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
return fData.getStyles(getPositionOfLine(line));
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return fData.getWidth();
|
||||
}
|
||||
|
||||
public ITerminalTextDataSnapshot makeSnapshot() {
|
||||
return fData.makeSnapshot();
|
||||
}
|
||||
private void cleanLines(int line, int len) {
|
||||
for (int i = line; i < line+len; i++) {
|
||||
fData.cleanLine(getPositionOfLine(i));
|
||||
}
|
||||
}
|
||||
public void scroll(int startLine, int size, int shift) {
|
||||
assert (startLine>=0 && startLine+size<=fHeight) || throwRuntimeException();
|
||||
if(shift>=fMaxHeight || -shift>=fMaxHeight) {
|
||||
cleanLines(startLine, fMaxHeight-startLine);
|
||||
return;
|
||||
}
|
||||
if(size==fHeight) {
|
||||
// This is the case this class is optimized for!
|
||||
moveOffset(-shift);
|
||||
// we only have to clean the lines that appear by the move
|
||||
if(shift<0) {
|
||||
cleanLines(Math.max(startLine, startLine+size+shift),Math.min(-shift, getHeight()-startLine));
|
||||
} else {
|
||||
cleanLines(startLine, Math.min(shift, getHeight()-startLine));
|
||||
}
|
||||
} else {
|
||||
// we have to copy the lines.
|
||||
if(shift<0) {
|
||||
// move the region up
|
||||
// shift is negative!!
|
||||
for (int i = startLine; i < startLine+size+shift; i++) {
|
||||
fData.copyLine(fData, getPositionOfLine(i-shift), getPositionOfLine(i));
|
||||
}
|
||||
// then clean the opened lines
|
||||
cleanLines(Math.max(0, startLine+size+shift),Math.min(-shift, getHeight()-startLine));
|
||||
} else {
|
||||
for (int i = startLine+size-1; i >=startLine && i-shift>=0; i--) {
|
||||
fData.copyLine(fData, getPositionOfLine(i-shift), getPositionOfLine(i));
|
||||
}
|
||||
cleanLines(startLine, Math.min(shift, getHeight()-startLine));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setChar(int line, int column, char c, Style style) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
fData.setChar(getPositionOfLine(line), column, c, style);
|
||||
}
|
||||
|
||||
public void setChars(int line, int column, char[] chars, int start, int len, Style style) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
fData.setChars(getPositionOfLine(line), column, chars, start, len, style);
|
||||
}
|
||||
|
||||
public void setChars(int line, int column, char[] chars, Style style) {
|
||||
assert (line>=0 && line<fHeight) || throwRuntimeException();
|
||||
fData.setChars(getPositionOfLine(line), column, chars, style);
|
||||
}
|
||||
|
||||
public void setDimensions(int height, int width) {
|
||||
assert height>=0 || throwRuntimeException();
|
||||
assert width>=0 || throwRuntimeException();
|
||||
if(height > fMaxHeight)
|
||||
setMaxHeight(height);
|
||||
fHeight=height;
|
||||
if(width!=fData.getWidth())
|
||||
fData.setDimensions(fMaxHeight, width);
|
||||
}
|
||||
|
||||
public void setMaxHeight(int maxHeight) {
|
||||
assert maxHeight>=fHeight || throwRuntimeException();
|
||||
// move everything to offset0
|
||||
int start=getPositionOfLine(0);
|
||||
if(start!=0) {
|
||||
// invent a more efficient algorithm....
|
||||
ITerminalTextData buffer=new TerminalTextDataStore();
|
||||
// create a buffer with the expected height
|
||||
buffer.setDimensions(maxHeight, getWidth());
|
||||
int n=Math.min(fMaxHeight-start,maxHeight);
|
||||
// copy the first part
|
||||
buffer.copyRange(fData, start, 0, n);
|
||||
// copy the second part
|
||||
if(n<maxHeight)
|
||||
buffer.copyRange(fData, 0, n, Math.min(fMaxHeight-n,maxHeight-n));
|
||||
// copy the buffer back to our data
|
||||
fData.copy(buffer);
|
||||
shiftOffset(-start);
|
||||
} else {
|
||||
fData.setDimensions(maxHeight, fData.getWidth());
|
||||
}
|
||||
fMaxHeight=maxHeight;
|
||||
}
|
||||
public int getCursorColumn() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public int getCursorLine() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void setCursorColumn(int column) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void setCursorLine(int line) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,299 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
* The public methods of this class have to be called from one thread!
|
||||
*
|
||||
* Threading considerations:
|
||||
* This class is <b>not threadsafe</b>!
|
||||
*/
|
||||
class TerminalTextDataSnapshot implements ITerminalTextDataSnapshot {
|
||||
/**
|
||||
* The changes of the current snapshot relative to the
|
||||
* previous snapshot
|
||||
*/
|
||||
volatile ISnapshotChanges fCurrentChanges;
|
||||
/**
|
||||
* Keeps track of changes that happened since the current
|
||||
* snapshot has been made.
|
||||
*/
|
||||
ISnapshotChanges fFutureChanges;
|
||||
/**
|
||||
* Is used as lock and is the reference to the terminal we take snapshots from.
|
||||
*/
|
||||
final TerminalTextData fTerminal;
|
||||
/**
|
||||
* A snapshot copy of of fTerminal
|
||||
*/
|
||||
// snapshot does not need internal synchronisation
|
||||
final TerminalTextDataWindow fSnapshot;
|
||||
// this variable is synchronized on fTerminal!
|
||||
private SnapshotOutOfDateListener[] fListener=new SnapshotOutOfDateListener[0];
|
||||
// this variable is synchronized on fTerminal!
|
||||
private boolean fListenersNeedNotify;
|
||||
private int fInterestWindowSize;
|
||||
private int fInterestWindowStartLine;
|
||||
|
||||
TerminalTextDataSnapshot(TerminalTextData terminal) {
|
||||
fSnapshot = new TerminalTextDataWindow();
|
||||
fTerminal = terminal;
|
||||
fCurrentChanges = new SnapshotChanges(fTerminal.getHeight());
|
||||
fCurrentChanges.setTerminalChanged();
|
||||
fFutureChanges = new SnapshotChanges(fTerminal.getHeight());
|
||||
fFutureChanges.markLinesChanged(0, fTerminal.getHeight());
|
||||
fListenersNeedNotify=true;
|
||||
fInterestWindowSize=-1;
|
||||
}
|
||||
/**
|
||||
* This is used in asserts to throw an {@link RuntimeException}.
|
||||
* This is useful for tests.
|
||||
* @return never -- throws an exception
|
||||
*/
|
||||
private boolean throwRuntimeException() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
public void detach() {
|
||||
fTerminal.removeSnapshot(this);
|
||||
}
|
||||
|
||||
public boolean isOutOfDate() {
|
||||
// this is called from fTerminal, therefore we lock on fTerminal
|
||||
synchronized (fTerminal) {
|
||||
return fFutureChanges.hasChanged();
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#snapshot()
|
||||
*/
|
||||
public void updateSnapshot(boolean detectScrolling) {
|
||||
// make sure terminal does not change while we make the snapshot
|
||||
synchronized (fTerminal) {
|
||||
// let's make the future changes current
|
||||
fCurrentChanges=fFutureChanges;
|
||||
fFutureChanges=new SnapshotChanges(fTerminal.getHeight());
|
||||
fFutureChanges.setInterestWindow(fInterestWindowStartLine, fInterestWindowSize);
|
||||
// and update the snapshot
|
||||
if(fSnapshot.getHeight()!=fTerminal.getHeight()||fSnapshot.getWidth()!=fTerminal.getWidth()) {
|
||||
if(fInterestWindowSize==-1)
|
||||
fSnapshot.setWindow(0, fTerminal.getHeight());
|
||||
// if the dimensions have changed, we need a full copy
|
||||
fSnapshot.copy(fTerminal);
|
||||
// and we mark all lines as changed
|
||||
fCurrentChanges.setAllChanged(fTerminal.getHeight());
|
||||
} else {
|
||||
// first we do the scroll on the copy
|
||||
int start=fCurrentChanges.getScrollWindowStartLine();
|
||||
int lines=Math.min(fCurrentChanges.getScrollWindowSize(), fSnapshot.getHeight()-start);
|
||||
fSnapshot.scroll(start, lines, fCurrentChanges.getScrollWindowShift());
|
||||
// and then create the snapshot of the changed lines
|
||||
fCurrentChanges.copyChangedLines(fSnapshot, fTerminal);
|
||||
}
|
||||
fListenersNeedNotify=true;
|
||||
fSnapshot.setCursorLine(fTerminal.getCursorLine());
|
||||
fSnapshot.setCursorColumn(fTerminal.getCursorColumn());
|
||||
}
|
||||
if(!detectScrolling) {
|
||||
// let's pretend there was no scrolling and
|
||||
// convert the scrolling into line changes
|
||||
fCurrentChanges.convertScrollingIntoChanges();
|
||||
}
|
||||
}
|
||||
|
||||
public char getChar(int line, int column) {
|
||||
return fSnapshot.getChar(line, column);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return fSnapshot.getHeight();
|
||||
}
|
||||
|
||||
public LineSegment[] getLineSegments(int line, int column, int len) {
|
||||
return fSnapshot.getLineSegments(line, column, len);
|
||||
}
|
||||
|
||||
public Style getStyle(int line, int column) {
|
||||
return fSnapshot.getStyle(line, column);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return fSnapshot.getWidth();
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getFirstChangedLine()
|
||||
*/
|
||||
public int getFirstChangedLine() {
|
||||
return fCurrentChanges.getFirstChangedLine();
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getLastChangedLine()
|
||||
*/
|
||||
public int getLastChangedLine() {
|
||||
return fCurrentChanges.getLastChangedLine();
|
||||
}
|
||||
|
||||
public boolean hasLineChanged(int line) {
|
||||
return fCurrentChanges.hasLineChanged(line);
|
||||
}
|
||||
public boolean hasDimensionsChanged() {
|
||||
return fCurrentChanges.hasDimensionsChanged();
|
||||
}
|
||||
public boolean hasTerminalChanged() {
|
||||
return fCurrentChanges.hasTerminalChanged();
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getScrollChangeY()
|
||||
*/
|
||||
public int getScrollWindowStartLine() {
|
||||
return fCurrentChanges.getScrollWindowStartLine();
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getScrollChangeN()
|
||||
*/
|
||||
public int getScrollWindowSize() {
|
||||
return fCurrentChanges.getScrollWindowSize();
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getScrollChangeShift()
|
||||
*/
|
||||
public int getScrollWindowShift() {
|
||||
return fCurrentChanges.getScrollWindowShift();
|
||||
}
|
||||
|
||||
/**
|
||||
* Announces a change in line line
|
||||
* @param line
|
||||
*/
|
||||
void markLineChanged(int line) {
|
||||
// threading
|
||||
fFutureChanges.markLineChanged(line);
|
||||
fFutureChanges.setTerminalChanged();
|
||||
notifyListers();
|
||||
}
|
||||
/**
|
||||
* Announces a change of n lines beginning with line line
|
||||
* @param line
|
||||
* @param n
|
||||
*/
|
||||
void markLinesChanged(int line,int n) {
|
||||
fFutureChanges.markLinesChanged(line,n);
|
||||
fFutureChanges.setTerminalChanged();
|
||||
notifyListers();
|
||||
}
|
||||
|
||||
void markDimensionsChanged() {
|
||||
fFutureChanges.markDimensionsChanged();
|
||||
fFutureChanges.setTerminalChanged();
|
||||
notifyListers();
|
||||
}
|
||||
void markCursorChanged() {
|
||||
fFutureChanges.markCursorChanged();
|
||||
fFutureChanges.setTerminalChanged();
|
||||
notifyListers();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param startLine
|
||||
* @param size
|
||||
* @param shift
|
||||
*/
|
||||
void scroll(int startLine, int size, int shift) {
|
||||
fFutureChanges.scroll(startLine,size,shift);
|
||||
fFutureChanges.setTerminalChanged();
|
||||
notifyListers();
|
||||
}
|
||||
/**
|
||||
* Notifies listeners about the change
|
||||
*/
|
||||
private void notifyListers() {
|
||||
// this code has to be called from a block synchronized on fTerminal
|
||||
synchronized (fTerminal) {
|
||||
if(fListenersNeedNotify) {
|
||||
for (int i = 0; i < fListener.length; i++) {
|
||||
fListener[i].snapshotOutOfDate(this);
|
||||
}
|
||||
fListenersNeedNotify=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public ITerminalTextDataSnapshot makeSnapshot() {
|
||||
return fSnapshot.makeSnapshot();
|
||||
}
|
||||
|
||||
synchronized public void addListener(SnapshotOutOfDateListener listener) {
|
||||
List list=new ArrayList();
|
||||
list.addAll(Arrays.asList(fListener));
|
||||
list.add(listener);
|
||||
fListener=(SnapshotOutOfDateListener[]) list.toArray(new SnapshotOutOfDateListener[list.size()]);
|
||||
}
|
||||
|
||||
synchronized public void removeListener(SnapshotOutOfDateListener listener) {
|
||||
List list=new ArrayList();
|
||||
list.addAll(Arrays.asList(fListener));
|
||||
list.remove(listener);
|
||||
fListener=(SnapshotOutOfDateListener[]) list.toArray(new SnapshotOutOfDateListener[list.size()]);
|
||||
}
|
||||
public String toString() {
|
||||
return fSnapshot.toString();
|
||||
}
|
||||
|
||||
|
||||
public int getInterestWindowSize() {
|
||||
return fInterestWindowSize;
|
||||
}
|
||||
|
||||
|
||||
public int getInterestWindowStartLine() {
|
||||
return fInterestWindowStartLine;
|
||||
}
|
||||
|
||||
public void setInterestWindow(int startLine, int size) {
|
||||
assert startLine>=0 || throwRuntimeException();
|
||||
assert size>=0 || throwRuntimeException();
|
||||
fInterestWindowStartLine=startLine;
|
||||
fInterestWindowSize=size;
|
||||
fSnapshot.setWindow(startLine, size);
|
||||
fFutureChanges.setInterestWindow(startLine, size);
|
||||
notifyListers();
|
||||
}
|
||||
|
||||
|
||||
public char[] getChars(int line) {
|
||||
return fSnapshot.getChars(line);
|
||||
}
|
||||
|
||||
|
||||
public Style[] getStyles(int line) {
|
||||
return fSnapshot.getStyles(line);
|
||||
}
|
||||
public int getCursorColumn() {
|
||||
return fSnapshot.getCursorColumn();
|
||||
}
|
||||
public int getCursorLine() {
|
||||
return fSnapshot.getCursorLine();
|
||||
}
|
||||
public ITerminalTextData getTerminalTextData() {
|
||||
return fTerminal;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,333 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
* This class is thread safe.
|
||||
*
|
||||
*/
|
||||
public class TerminalTextDataStore implements ITerminalTextData {
|
||||
private char[][] fChars;
|
||||
private Style[][] fStyle;
|
||||
private int fWidth;
|
||||
private int fHeight;
|
||||
private int fMaxHeight;
|
||||
private int fCursorColumn;
|
||||
private int fCursorLine;
|
||||
public TerminalTextDataStore() {
|
||||
fChars=new char[0][];
|
||||
fStyle=new Style[0][];
|
||||
fWidth=0;
|
||||
}
|
||||
/**
|
||||
* This is used in asserts to throw an {@link RuntimeException}.
|
||||
* This is useful for tests.
|
||||
* @return never -- throws an exception
|
||||
*/
|
||||
private boolean throwRuntimeException() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getWidth()
|
||||
*/
|
||||
public int getWidth() {
|
||||
return fWidth;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getHeight()
|
||||
*/
|
||||
public int getHeight() {
|
||||
return fHeight;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#setDimensions(int, int)
|
||||
*/
|
||||
public void setDimensions(int height, int width) {
|
||||
assert height>=0 || throwRuntimeException();
|
||||
assert width>=0 || throwRuntimeException();
|
||||
// just extend the region
|
||||
if(height>fChars.length) {
|
||||
int h=4*height/3;
|
||||
if(fMaxHeight>0 && h>fMaxHeight)
|
||||
h=fMaxHeight;
|
||||
fStyle=(Style[][]) resizeArray(fStyle, height);
|
||||
fChars=(char[][]) resizeArray(fChars, height);
|
||||
}
|
||||
// clean the new lines
|
||||
if(height>fHeight) {
|
||||
for (int i = fHeight; i < height; i++) {
|
||||
fStyle[i]=null;
|
||||
fChars[i]=null;
|
||||
}
|
||||
}
|
||||
// set dimensions after successful resize!
|
||||
fWidth=width;
|
||||
fHeight=height;
|
||||
}
|
||||
/**
|
||||
* Reallocates an array with a new size, and copies the contents of the old
|
||||
* array to the new array.
|
||||
*
|
||||
* @param origArray the old array, to be reallocated.
|
||||
* @param newSize the new array size.
|
||||
* @return A new array with the same contents (chopped off if needed or filled with 0 or null).
|
||||
*/
|
||||
private Object resizeArray(Object origArray, int newSize) {
|
||||
int oldSize = Array.getLength(origArray);
|
||||
if(oldSize==newSize)
|
||||
return origArray;
|
||||
Class elementType = origArray.getClass().getComponentType();
|
||||
Object newArray = Array.newInstance(elementType, newSize);
|
||||
int preserveLength = Math.min(oldSize, newSize);
|
||||
if (preserveLength > 0)
|
||||
System.arraycopy(origArray, 0, newArray, 0, preserveLength);
|
||||
return newArray;
|
||||
}
|
||||
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getLineSegments(int, int, int)
|
||||
*/
|
||||
public LineSegment[] getLineSegments(int line, int column, int len) {
|
||||
// get the styles and chars for this line
|
||||
Style[] styles=fStyle[line];
|
||||
char[] chars=fChars[line];
|
||||
int col=column;
|
||||
int n=column+len;
|
||||
|
||||
// expand the line if needed....
|
||||
if(styles==null)
|
||||
styles=new Style[n];
|
||||
else if(styles.length<n)
|
||||
styles=(Style[]) resizeArray(styles, n);
|
||||
|
||||
if(chars==null)
|
||||
chars=new char[n];
|
||||
else if(chars.length<n)
|
||||
chars=(char[]) resizeArray(chars, n);
|
||||
|
||||
// and create the line segments
|
||||
Style style=styles[column];
|
||||
List segments=new ArrayList();
|
||||
for (int i = column; i < n; i++) {
|
||||
if(styles[i]!=style) {
|
||||
segments.add(new LineSegment(col,new String(chars,col,i-col),style));
|
||||
style=styles[i];
|
||||
col=i;
|
||||
}
|
||||
}
|
||||
if(col < n) {
|
||||
segments.add(new LineSegment(col,new String(chars,col,n-col),style));
|
||||
}
|
||||
return (LineSegment[]) segments.toArray(new LineSegment[segments.size()]);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getChar(int, int)
|
||||
*/
|
||||
public char getChar(int line, int column) {
|
||||
assert column<fWidth || throwRuntimeException();
|
||||
if(fChars[line]==null||column>=fChars[line].length)
|
||||
return 0;
|
||||
return fChars[line][column];
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getStyle(int, int)
|
||||
*/
|
||||
public Style getStyle(int line, int column) {
|
||||
assert column<fWidth || throwRuntimeException();
|
||||
if(fStyle[line]==null || column>=fStyle[line].length)
|
||||
return null;
|
||||
return fStyle[line][column];
|
||||
}
|
||||
|
||||
void ensureLineLength(int iLine, int length) {
|
||||
if(length>fWidth)
|
||||
throw new RuntimeException();
|
||||
if(fChars[iLine]==null) {
|
||||
fChars[iLine]=new char[length];
|
||||
} else if(fChars[iLine].length<length) {
|
||||
fChars[iLine]=(char[]) resizeArray(fChars[iLine],length);
|
||||
}
|
||||
if(fStyle[iLine]==null) {
|
||||
fStyle[iLine]=new Style[length];
|
||||
} else if(fStyle[iLine].length<length) {
|
||||
fStyle[iLine]=(Style[]) resizeArray(fStyle[iLine],length);
|
||||
}
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#setChar(int, int, char, org.eclipse.tm.internal.terminal.text.Style)
|
||||
*/
|
||||
public void setChar(int line, int column, char c, Style style) {
|
||||
ensureLineLength(line,column+1);
|
||||
fChars[line][column]=c;
|
||||
fStyle[line][column]=style;
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#setChars(int, int, char[], org.eclipse.tm.internal.terminal.text.Style)
|
||||
*/
|
||||
public void setChars(int line, int column, char[] chars, Style style) {
|
||||
setChars(line,column,chars,0,chars.length,style);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#setChars(int, int, char[], int, int, org.eclipse.tm.internal.terminal.text.Style)
|
||||
*/
|
||||
public void setChars(int line, int column, char[] chars, int start, int len, Style style) {
|
||||
ensureLineLength(line,column+len);
|
||||
for (int i = 0; i < len; i++) {
|
||||
fChars[line][column+i]=chars[i+start];
|
||||
fStyle[line][column+i]=style;
|
||||
}
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#scroll(int, int, int)
|
||||
*/
|
||||
public void scroll(int startLine, int size, int shift) {
|
||||
assert startLine+size <= getHeight() || throwRuntimeException();
|
||||
if(shift<0) {
|
||||
// move the region up
|
||||
// shift is negative!!
|
||||
for (int i = startLine; i < startLine+size+shift; i++) {
|
||||
fChars[i]=fChars[i-shift];
|
||||
fStyle[i]=fStyle[i-shift];
|
||||
}
|
||||
// then clean the opened lines
|
||||
cleanLines(Math.max(startLine, startLine+size+shift),Math.min(-shift, getHeight()-startLine));
|
||||
// cleanLines(Math.max(0, startLine+size+shift),Math.min(-shift, getHeight()-startLine));
|
||||
} else {
|
||||
for (int i = startLine+size-1; i >=startLine && i-shift>=0; i--) {
|
||||
fChars[i]=fChars[i-shift];
|
||||
fStyle[i]=fStyle[i-shift];
|
||||
}
|
||||
cleanLines(startLine, Math.min(shift, getHeight()-startLine));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Replaces the lines with new empty data
|
||||
* @param line
|
||||
* @param len
|
||||
*/
|
||||
private void cleanLines(int line, int len) {
|
||||
for (int i = line; i < line+len; i++) {
|
||||
fChars[i]=null;
|
||||
fStyle[i]=null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @return a text representation of the object.
|
||||
* Lines are separated by '\n'. No style information is returned.
|
||||
*/
|
||||
public String toString() {
|
||||
StringBuffer buff=new StringBuffer();
|
||||
for (int line = 0; line < getHeight(); line++) {
|
||||
if(line>0)
|
||||
buff.append("\n"); //$NON-NLS-1$
|
||||
for (int column = 0; column < fWidth; column++) {
|
||||
buff.append(getChar(line, column));
|
||||
}
|
||||
}
|
||||
return buff.toString();
|
||||
}
|
||||
|
||||
|
||||
public ITerminalTextDataSnapshot makeSnapshot() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public void addLine() {
|
||||
if(fMaxHeight>0 && getHeight()<fMaxHeight) {
|
||||
setDimensions(getHeight()+1, getWidth());
|
||||
} else {
|
||||
scroll(0,getHeight(),-1);
|
||||
}
|
||||
}
|
||||
|
||||
public void copy(ITerminalTextData source) {
|
||||
fWidth=source.getWidth();
|
||||
int n=source.getHeight();
|
||||
if(getHeight()!=n) {
|
||||
fChars=new char[n][];
|
||||
fStyle=new Style[n][];
|
||||
}
|
||||
for (int i = 0; i < n; i++) {
|
||||
fChars[i]=source.getChars(i);
|
||||
fStyle[i]=source.getStyles(i);
|
||||
}
|
||||
fHeight=n;
|
||||
fCursorLine=source.getCursorLine();
|
||||
fCursorColumn=source.getCursorColumn();
|
||||
}
|
||||
public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine,int length) {
|
||||
for (int i = 0; i < length; i++) {
|
||||
fChars[i+destStartLine]=source.getChars(i+sourceStartLine);
|
||||
fStyle[i+destStartLine]=source.getStyles(i+sourceStartLine);
|
||||
}
|
||||
}
|
||||
|
||||
public void copyLine(ITerminalTextData source, int sourceLine, int destLine) {
|
||||
fChars[destLine]=source.getChars(sourceLine);
|
||||
fStyle[destLine]=source.getStyles(sourceLine);
|
||||
}
|
||||
|
||||
public char[] getChars(int line) {
|
||||
if(fChars[line]==null)
|
||||
return null;
|
||||
return (char[]) fChars[line].clone();
|
||||
}
|
||||
|
||||
public Style[] getStyles(int line) {
|
||||
if(fStyle[line]==null)
|
||||
return null;
|
||||
return (Style[]) fStyle[line].clone();
|
||||
}
|
||||
|
||||
public void setLine(int line, char[] chars, Style[] styles) {
|
||||
fChars[line]=(char[]) chars.clone();
|
||||
fStyle[line]=(Style[]) styles.clone();
|
||||
}
|
||||
|
||||
public void setMaxHeight(int height) {
|
||||
fMaxHeight=height;
|
||||
}
|
||||
|
||||
public int getMaxHeight() {
|
||||
return fMaxHeight;
|
||||
}
|
||||
|
||||
public void cleanLine(int line) {
|
||||
fChars[line]=null;
|
||||
fStyle[line]=null;
|
||||
}
|
||||
public int getCursorColumn() {
|
||||
return fCursorColumn;
|
||||
}
|
||||
public int getCursorLine() {
|
||||
return fCursorLine;
|
||||
}
|
||||
public void setCursorColumn(int column) {
|
||||
fCursorColumn=column;
|
||||
}
|
||||
public void setCursorLine(int line) {
|
||||
fCursorLine=line;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,198 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.model;
|
||||
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextData;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
* This class stores the data only within a window {@link #setWindow(int, int)} and
|
||||
* {@link #getWindowStartLine()} and {@link #getWindowSize()}. Everything outside
|
||||
* the is <code>char=='\000'</code> and <code>style=null</code>.
|
||||
*
|
||||
*/
|
||||
public class TerminalTextDataWindow implements ITerminalTextData {
|
||||
final ITerminalTextData fData;
|
||||
int fWindowStartLine;
|
||||
int fWindowSize;
|
||||
int fHeight;
|
||||
int fMaxHeight;
|
||||
public TerminalTextDataWindow(ITerminalTextData data) {
|
||||
fData=data;
|
||||
}
|
||||
public TerminalTextDataWindow() {
|
||||
this(new TerminalTextDataStore());
|
||||
}
|
||||
/**
|
||||
* This is used in asserts to throw an {@link RuntimeException}.
|
||||
* This is useful for tests.
|
||||
* @return never -- throws an exception
|
||||
*/
|
||||
private boolean throwRuntimeException() {
|
||||
throw new RuntimeException();
|
||||
}
|
||||
/**
|
||||
* @param line
|
||||
* @return true if the line is within the window
|
||||
*/
|
||||
boolean isInWindow(int line) {
|
||||
return line>=fWindowStartLine && line<fWindowStartLine+fWindowSize;
|
||||
}
|
||||
public char getChar(int line, int column) {
|
||||
if(!isInWindow(line))
|
||||
return 0;
|
||||
return fData.getChar(line-fWindowStartLine, column);
|
||||
}
|
||||
|
||||
public char[] getChars(int line) {
|
||||
if(!isInWindow(line))
|
||||
return null;
|
||||
return fData.getChars(line-fWindowStartLine);
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return fHeight;
|
||||
}
|
||||
|
||||
public LineSegment[] getLineSegments(int line, int startCol, int numberOfCols) {
|
||||
if(!isInWindow(line))
|
||||
return new LineSegment[]{new LineSegment(startCol,new String(new char[numberOfCols]),null)};
|
||||
return fData.getLineSegments(line-fWindowStartLine, startCol, numberOfCols);
|
||||
}
|
||||
|
||||
public int getMaxHeight() {
|
||||
return fMaxHeight;
|
||||
}
|
||||
|
||||
public Style getStyle(int line, int column) {
|
||||
if(!isInWindow(line))
|
||||
return null;
|
||||
return fData.getStyle(line-fWindowStartLine, column);
|
||||
}
|
||||
|
||||
public Style[] getStyles(int line) {
|
||||
if(!isInWindow(line))
|
||||
return null;
|
||||
return fData.getStyles(line-fWindowStartLine);
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return fData.getWidth();
|
||||
}
|
||||
|
||||
public ITerminalTextDataSnapshot makeSnapshot() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
public void addLine() {
|
||||
if(fMaxHeight>0 && getHeight()<fMaxHeight) {
|
||||
setDimensions(getHeight()+1, getWidth());
|
||||
} else {
|
||||
scroll(0,getHeight(),-1);
|
||||
}
|
||||
}
|
||||
public void copy(ITerminalTextData source) {
|
||||
// we inherit the dimensions of the source
|
||||
setDimensions(source.getHeight(), source.getWidth());
|
||||
int n=Math.min(fWindowSize, source.getHeight()-fWindowStartLine);
|
||||
if(n>0)
|
||||
fData.copyRange(source, fWindowStartLine, 0, n);
|
||||
}
|
||||
public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine, int length) {
|
||||
int n=length;
|
||||
int dStart=destStartLine-fWindowStartLine;
|
||||
int sStart=sourceStartLine;
|
||||
// if start outside our range, cut the length to copy
|
||||
if(dStart<0) {
|
||||
n+=dStart;
|
||||
sStart-=dStart;
|
||||
dStart=0;
|
||||
}
|
||||
// do not exceed the window size
|
||||
n=Math.min(n,fWindowSize);
|
||||
if(n>0)
|
||||
fData.copyRange(source, sStart, dStart, n);
|
||||
|
||||
}
|
||||
public void copyLine(ITerminalTextData source, int sourceLine, int destLine) {
|
||||
if(isInWindow(destLine))
|
||||
fData.copyLine(source, sourceLine, destLine-fWindowStartLine);
|
||||
}
|
||||
public void scroll(int startLine, int size, int shift) {
|
||||
assert (startLine>=0 && startLine+size<=fHeight) || throwRuntimeException();
|
||||
int n=size;
|
||||
int start=startLine-fWindowStartLine;
|
||||
// if start outside our range, cut the length to copy
|
||||
if(start<0) {
|
||||
n+=start;
|
||||
start=0;
|
||||
}
|
||||
n=Math.min(n,fWindowSize-start);
|
||||
// do not exceed the window size
|
||||
if(n>0)
|
||||
fData.scroll(start, n, shift);
|
||||
}
|
||||
public void setChar(int line, int column, char c, Style style) {
|
||||
if(!isInWindow(line))
|
||||
return;
|
||||
fData.setChar(line-fWindowStartLine, column, c, style);
|
||||
}
|
||||
public void setChars(int line, int column, char[] chars, int start, int len, Style style) {
|
||||
if(!isInWindow(line))
|
||||
return;
|
||||
fData.setChars(line-fWindowStartLine, column, chars, start, len, style);
|
||||
}
|
||||
public void setChars(int line, int column, char[] chars, Style style) {
|
||||
if(!isInWindow(line))
|
||||
return;
|
||||
fData.setChars(line-fWindowStartLine, column, chars, style);
|
||||
}
|
||||
public void setDimensions(int height, int width) {
|
||||
assert height>=0 || throwRuntimeException();
|
||||
fData.setDimensions(fWindowSize, width);
|
||||
fHeight=height;
|
||||
}
|
||||
public void setMaxHeight(int height) {
|
||||
fMaxHeight=height;
|
||||
}
|
||||
public void setWindow(int startLine, int size) {
|
||||
// assert startLine+size<=getHeight()||throwRuntimeException();
|
||||
fWindowStartLine=startLine;
|
||||
fWindowSize=size;
|
||||
fData.setDimensions(fWindowSize, getWidth());
|
||||
}
|
||||
public int getWindowStartLine() {
|
||||
return fWindowStartLine;
|
||||
}
|
||||
public int getWindowSize() {
|
||||
return fWindowSize;
|
||||
}
|
||||
public void setHeight(int height) {
|
||||
fHeight = height;
|
||||
}
|
||||
public void cleanLine(int line) {
|
||||
if(isInWindow(line))
|
||||
fData.cleanLine(line-fWindowStartLine);
|
||||
}
|
||||
public int getCursorColumn() {
|
||||
return fData.getCursorColumn();
|
||||
}
|
||||
public int getCursorLine() {
|
||||
return fData.getCursorLine();
|
||||
}
|
||||
public void setCursorColumn(int column) {
|
||||
fData.setCursorColumn(column);
|
||||
}
|
||||
public void setCursorLine(int line) {
|
||||
fData.setCursorLine(line);
|
||||
}
|
||||
}
|
|
@ -168,7 +168,8 @@ public final class Logger {
|
|||
*/
|
||||
public static final void logException(Exception ex) {
|
||||
// log in eclipse error log
|
||||
TerminalPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, TerminalPlugin.PLUGIN_ID, IStatus.OK, ex.getMessage(), ex));
|
||||
if(TerminalPlugin.getDefault()!=null)
|
||||
TerminalPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, TerminalPlugin.PLUGIN_ID, IStatus.OK, ex.getMessage(), ex));
|
||||
// Read my own stack to get the class name, method name, and line number
|
||||
// of
|
||||
// where this method was called.
|
||||
|
@ -189,6 +190,8 @@ public final class Logger {
|
|||
+ "." + methodName + ":" + lineNumber + ": " + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
|
||||
"Caught exception: " + ex); //$NON-NLS-1$
|
||||
ex.printStackTrace(tmpStream);
|
||||
} else {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,289 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
|
||||
abstract public class AbstractTextCanvasModel implements ITextCanvasModel {
|
||||
protected List fListeners = new ArrayList();
|
||||
private int fCursorLine;
|
||||
private int fCursorColumn;
|
||||
private boolean fShowCursor;
|
||||
private long fCursorTime;
|
||||
private boolean fCursorIsEnabled;
|
||||
private final ITerminalTextDataSnapshot fSnapshot;
|
||||
private int fLines;
|
||||
|
||||
private int fSelectionStartLine;
|
||||
private int fSeletionEndLine;
|
||||
private int fSelectionStartCoumn;
|
||||
private int fSelectionEndColumn;
|
||||
private ITerminalTextDataSnapshot fSelectionSnapshot;
|
||||
|
||||
public AbstractTextCanvasModel(ITerminalTextDataSnapshot snapshot) {
|
||||
fSnapshot=snapshot;
|
||||
fLines=fSnapshot.getHeight();
|
||||
}
|
||||
public void addCellCanvasModelListener(ITextCanvasModelListener listener) {
|
||||
fListeners.add(listener);
|
||||
}
|
||||
|
||||
public void removeCellCanvasModelListener(ITextCanvasModelListener listener) {
|
||||
fListeners.remove(listener);
|
||||
}
|
||||
|
||||
protected void fireCellRangeChanged(int x, int y, int width, int height) {
|
||||
for (Iterator iter = fListeners.iterator(); iter.hasNext();) {
|
||||
ITextCanvasModelListener listener = (ITextCanvasModelListener) iter.next();
|
||||
listener.rangeChanged(x, y, width, height);
|
||||
}
|
||||
}
|
||||
protected void fireDimensionsChanged( int width,int height) {
|
||||
for (Iterator iter = fListeners.iterator(); iter.hasNext();) {
|
||||
ITextCanvasModelListener listener = (ITextCanvasModelListener) iter.next();
|
||||
listener.dimensionsChanged(width,height);
|
||||
}
|
||||
|
||||
}
|
||||
protected void fireTerminalDataChanged() {
|
||||
for (Iterator iter = fListeners.iterator(); iter.hasNext();) {
|
||||
ITextCanvasModelListener listener = (ITextCanvasModelListener) iter.next();
|
||||
listener.terminalDataChanged();
|
||||
}
|
||||
|
||||
}
|
||||
public ITerminalTextDataReadOnly getTerminalText() {
|
||||
return fSnapshot;
|
||||
}
|
||||
protected ITerminalTextDataSnapshot getSnapshot() {
|
||||
return fSnapshot;
|
||||
}
|
||||
protected void updateSnapshot() {
|
||||
if(fSnapshot.isOutOfDate()) {
|
||||
fSnapshot.updateSnapshot(false);
|
||||
if(fSnapshot.hasTerminalChanged())
|
||||
fireTerminalDataChanged();
|
||||
// TODO why does hasDimensionsChanged not work??????
|
||||
// if(fSnapshot.hasDimensionsChanged())
|
||||
// fireDimensionsChanged();
|
||||
if(fLines!=fSnapshot.getHeight()) {
|
||||
fireDimensionsChanged(fSnapshot.getWidth(),fSnapshot.getHeight());
|
||||
fLines=fSnapshot.getHeight();
|
||||
}
|
||||
int y=fSnapshot.getFirstChangedLine();
|
||||
// has any line changed?
|
||||
if(y<Integer.MAX_VALUE) {
|
||||
int height=fSnapshot.getLastChangedLine()-y+1;
|
||||
fireCellRangeChanged(0, y, fSnapshot.getWidth(), height);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* must be called from the UI thread
|
||||
*/
|
||||
public void update() {
|
||||
// do the poll....
|
||||
updateSnapshot();
|
||||
updateSelection();
|
||||
updateCursor();
|
||||
}
|
||||
|
||||
|
||||
public int getCursorColumn() {
|
||||
return fCursorColumn;
|
||||
}
|
||||
|
||||
public int getCursorLine() {
|
||||
return fCursorLine;
|
||||
}
|
||||
|
||||
public boolean isCursorOn() {
|
||||
return fShowCursor && fCursorIsEnabled;
|
||||
}
|
||||
/**
|
||||
* should be called regularly to draw an update of the
|
||||
* blinking cursor
|
||||
*/
|
||||
protected void updateCursor() {
|
||||
if(!fCursorIsEnabled)
|
||||
return;
|
||||
int cursorLine=getSnapshot().getCursorLine();
|
||||
int cursorColumn=getSnapshot().getCursorColumn();
|
||||
// if cursor at the end put it to the end of the
|
||||
// last line...
|
||||
if(cursorLine>=getSnapshot().getHeight()) {
|
||||
cursorLine=getSnapshot().getHeight()-1;
|
||||
cursorColumn=getSnapshot().getWidth()-1;
|
||||
}
|
||||
// has the cursor moved?
|
||||
if(fCursorLine!=cursorLine || fCursorColumn!=cursorColumn) {
|
||||
// hide the old cursor!
|
||||
fShowCursor=false;
|
||||
// clean the previous cursor
|
||||
fireCellRangeChanged(fCursorColumn, fCursorLine, 1, 1);
|
||||
// the cursor is shown when it moves!
|
||||
fShowCursor=true;
|
||||
fCursorTime=System.currentTimeMillis();
|
||||
fCursorLine=cursorLine;
|
||||
fCursorColumn=cursorColumn;
|
||||
// and draw the new cursor
|
||||
fireCellRangeChanged(fCursorColumn, fCursorLine, 1, 1);
|
||||
} else {
|
||||
long t=System.currentTimeMillis();
|
||||
// TODO make the cursor blink time customisable
|
||||
if(t-fCursorTime>500) {
|
||||
fShowCursor=!fShowCursor;
|
||||
fCursorTime=t;
|
||||
fireCellRangeChanged(fCursorColumn, fCursorLine, 1, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void setVisibleRectangle(int startLine, int startCol, int height, int width) {
|
||||
fSnapshot.setInterestWindow(Math.max(0,startLine), Math.max(1,Math.min(fSnapshot.getHeight(),height)));
|
||||
update();
|
||||
}
|
||||
protected void showCursor(boolean show) {
|
||||
fShowCursor=true;
|
||||
}
|
||||
public void setCursorEnabled(boolean visible) {
|
||||
fCursorTime=System.currentTimeMillis();
|
||||
fShowCursor=visible;
|
||||
fCursorIsEnabled=visible;
|
||||
fireCellRangeChanged(fCursorColumn, fCursorLine, 1, 1);
|
||||
}
|
||||
public boolean isCursorEnabled() {
|
||||
return fCursorIsEnabled;
|
||||
}
|
||||
|
||||
public Point getSelectionEnd() {
|
||||
if(fSelectionStartLine<0)
|
||||
return null;
|
||||
else
|
||||
return new Point(fSelectionEndColumn, fSeletionEndLine);
|
||||
}
|
||||
|
||||
public Point getSelectionStart() {
|
||||
if (fSelectionStartLine < 0)
|
||||
return null;
|
||||
else
|
||||
return new Point(fSelectionStartCoumn,fSelectionStartLine);
|
||||
}
|
||||
|
||||
public void setSelection(int startLine, int endLine, int startColumn, int endColumn) {
|
||||
assert(startLine<0 || startLine<=endLine);
|
||||
if(startLine>=0) {
|
||||
if(fSelectionSnapshot==null) {
|
||||
fSelectionSnapshot=fSnapshot.getTerminalTextData().makeSnapshot();
|
||||
fSelectionSnapshot.updateSnapshot(true);
|
||||
}
|
||||
} else if(fSelectionSnapshot!=null) {
|
||||
fSelectionSnapshot.detach();
|
||||
fSelectionSnapshot=null;
|
||||
}
|
||||
int oldStart=fSelectionStartLine;
|
||||
int oldEnd=fSeletionEndLine;
|
||||
fSelectionStartLine = startLine;
|
||||
fSeletionEndLine = endLine;
|
||||
fSelectionStartCoumn = startColumn;
|
||||
fSelectionEndColumn = endColumn;
|
||||
if(fSelectionSnapshot!=null) {
|
||||
fSelectionSnapshot.setInterestWindow(0, fSeletionEndLine);
|
||||
}
|
||||
int changedStart;
|
||||
int changedEnd;
|
||||
if(oldStart<0) {
|
||||
changedStart=fSelectionStartLine;
|
||||
changedEnd=fSeletionEndLine;
|
||||
} else if(fSelectionStartLine<0) {
|
||||
changedStart=oldStart;
|
||||
changedEnd=oldEnd;
|
||||
} else {
|
||||
changedStart=Math.min(oldStart, fSelectionStartLine);
|
||||
changedEnd=Math.max(oldEnd, fSeletionEndLine);
|
||||
}
|
||||
if(changedStart>=0) {
|
||||
fireCellRangeChanged(0, changedStart, fSnapshot.getWidth(), changedEnd-changedStart+1);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean hasLineSelection(int line) {
|
||||
if (fSelectionStartLine < 0)
|
||||
return false;
|
||||
else
|
||||
return line >= fSelectionStartLine && line <= fSeletionEndLine;
|
||||
}
|
||||
|
||||
public String getSelectedText() {
|
||||
if(fSelectionStartLine<0 || fSelectionSnapshot==null)
|
||||
return ""; //$NON-NLS-1$
|
||||
if(fSelectionStartLine<0 || fSelectionSnapshot==null)
|
||||
return ""; //$NON-NLS-1$
|
||||
StringBuffer buffer=new StringBuffer();
|
||||
for (int line = fSelectionStartLine; line <= fSeletionEndLine; line++) {
|
||||
String text;
|
||||
char[] chars=fSelectionSnapshot.getChars(line);
|
||||
if(chars!=null) {
|
||||
text=new String(chars);
|
||||
if(line==fSeletionEndLine)
|
||||
text=text.substring(0, Math.min(fSelectionEndColumn,text.length()));
|
||||
if(line==fSelectionStartLine)
|
||||
text=text.substring(Math.min(fSelectionStartCoumn,text.length()));
|
||||
// get rid of the empty space at the end of the lines
|
||||
text=text.replaceAll("\000+$",""); //$NON-NLS-1$//$NON-NLS-2$
|
||||
// null means space
|
||||
text=text.replace('\000', ' ');
|
||||
} else {
|
||||
text=""; //$NON-NLS-1$
|
||||
}
|
||||
buffer.append(text);
|
||||
if(line < fSeletionEndLine)
|
||||
buffer.append('\n');
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
private void updateSelection() {
|
||||
if (fSelectionSnapshot != null && fSelectionSnapshot.isOutOfDate()) {
|
||||
// let's see if the selection text has changed since the last snapshot
|
||||
String oldSelection = getSelectedText();
|
||||
fSelectionSnapshot.updateSnapshot(true);
|
||||
// has the selection moved?
|
||||
if (fSelectionSnapshot != null && fSelectionStartLine >= 0 && fSelectionSnapshot.getScrollWindowSize() > 0) {
|
||||
int start = fSelectionStartLine + fSelectionSnapshot.getScrollWindowShift();
|
||||
int end = fSeletionEndLine + fSelectionSnapshot.getScrollWindowShift();
|
||||
if (start < 0)
|
||||
if (end >= 0)
|
||||
start = 0;
|
||||
else
|
||||
start = -1;
|
||||
setSelection(start, end, fSelectionStartCoumn, fSelectionEndColumn);
|
||||
}
|
||||
// have lines inside the selection changed?
|
||||
if (fSelectionSnapshot != null && fSelectionSnapshot.getFirstChangedLine() <= fSeletionEndLine &&
|
||||
fSelectionSnapshot.getLastChangedLine() >= fSelectionStartLine) {
|
||||
// has the selected text changed?
|
||||
String newSelection = getSelectedText();
|
||||
if (!oldSelection.equals(newSelection))
|
||||
setSelection(-1, -1, -1, -1);
|
||||
}
|
||||
// update the observed window...
|
||||
if (fSelectionSnapshot != null)
|
||||
// todo make -1 to work!
|
||||
fSelectionSnapshot.setInterestWindow(0, fSeletionEndLine);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,183 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
|
||||
/**
|
||||
* A Grid based Canvas. The canvas has rows and columns.
|
||||
* CellPainting is done with the abstract method drawCell
|
||||
*/
|
||||
abstract public class GridCanvas extends VirtualCanvas {
|
||||
/** width of a cell */
|
||||
private int fCellWidth;
|
||||
/** height of a cell */
|
||||
private int fCellHeight;
|
||||
|
||||
public GridCanvas(Composite parent, int style) {
|
||||
super(parent, style);
|
||||
addListener(SWT.MouseWheel, new Listener() {
|
||||
public void handleEvent(Event event) {
|
||||
if(getVerticalBar().isVisible()) {
|
||||
int delta=-fCellHeight;
|
||||
if(event.count<0)
|
||||
delta=-delta;
|
||||
scrollYDelta(delta);
|
||||
}
|
||||
event.doit=false;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/** template method paint.
|
||||
* iterates over all cells in the clipping rectangle and paints them.
|
||||
*/
|
||||
protected void paint(GC gc) {
|
||||
Rectangle clipping=gc.getClipping();
|
||||
if(clipping.width==0 || clipping.height==0)
|
||||
return;
|
||||
Rectangle clientArea= getScreenRectInVirtualSpace();
|
||||
// Beginning coordinates
|
||||
int xOffset=clientArea.x;
|
||||
int yOffset=clientArea.y;
|
||||
int colFirst=virtualXToCell(xOffset+clipping.x);
|
||||
if(colFirst>getCols())
|
||||
colFirst=getCols();
|
||||
int rowFirst=virtualYToCell(yOffset+clipping.y);
|
||||
// End coordinates
|
||||
int colLast=virtualXToCell(xOffset+clipping.x+clipping.width+fCellWidth);
|
||||
if(colLast>getCols())
|
||||
colLast=getCols();
|
||||
int rowLast=virtualYToCell(yOffset+clipping.y+clipping.height+fCellHeight);
|
||||
if(rowLast>getRows())
|
||||
rowLast=getRows();
|
||||
// System.out.println(rowFirst+"->"+rowLast+" "+System.currentTimeMillis());
|
||||
// draw the cells
|
||||
for(int row=rowFirst;row<=rowLast;row++) {
|
||||
int cx=colFirst*fCellWidth-xOffset;
|
||||
int cy=row*fCellHeight-yOffset;
|
||||
drawLine(gc,row,cx,cy,colFirst,colLast);
|
||||
}
|
||||
paintUnoccupiedSpace(gc,clipping);
|
||||
}
|
||||
/**
|
||||
* @param gc
|
||||
* @param row the line to draw
|
||||
* @param x coordinate on screen
|
||||
* @param y coordinate on screen
|
||||
* @param colFirst first column to draw
|
||||
* @param colLast last column to draw
|
||||
*/
|
||||
abstract void drawLine(GC gc, int row, int x, int y, int colFirst, int colLast);
|
||||
|
||||
abstract protected int getRows();
|
||||
abstract protected int getCols();
|
||||
|
||||
protected void setCellWidth(int cellWidth) {
|
||||
fCellWidth = cellWidth;
|
||||
getHorizontalBar().setIncrement(fCellWidth);
|
||||
}
|
||||
|
||||
public int getCellWidth() {
|
||||
return fCellWidth;
|
||||
}
|
||||
|
||||
protected void setCellHeight(int cellHeight) {
|
||||
fCellHeight = cellHeight;
|
||||
getVerticalBar().setIncrement(fCellHeight);
|
||||
}
|
||||
|
||||
public int getCellHeight() {
|
||||
return fCellHeight;
|
||||
}
|
||||
|
||||
int virtualXToCell(int x) {
|
||||
return x/fCellWidth;
|
||||
}
|
||||
|
||||
int virtualYToCell(int y) {
|
||||
return y/fCellHeight;
|
||||
}
|
||||
|
||||
protected Point screenPointToCell(int x, int y) {
|
||||
x=screenXtoVirtual(x)/fCellWidth;
|
||||
y=screenYtoVirtual(y)/fCellHeight;
|
||||
return new Point(x,y);
|
||||
}
|
||||
|
||||
Point screenPointToCell(Point point) {
|
||||
return screenPointToCell(point.x,point.y);
|
||||
}
|
||||
|
||||
protected Point cellToOriginOnScreen(int x, int y) {
|
||||
x=virtualXtoScreen(fCellWidth*x);
|
||||
y=virtualYtoScreen(fCellHeight*y);
|
||||
return new Point(x,y);
|
||||
}
|
||||
|
||||
Point cellToOriginOnScreen(Point cell) {
|
||||
return cellToOriginOnScreen(cell.x,cell.y);
|
||||
}
|
||||
|
||||
Rectangle getCellScreenRect(Point cell) {
|
||||
return getCellScreenRect(cell.x,cell.y);
|
||||
}
|
||||
|
||||
Rectangle getCellScreenRect(int x, int y) {
|
||||
x=fCellWidth*virtualXtoScreen(x);
|
||||
y=fCellHeight*virtualYtoScreen(y);
|
||||
return new Rectangle(x,y,fCellWidth,fCellHeight);
|
||||
}
|
||||
|
||||
protected Rectangle getCellVirtualRect(Point cell) {
|
||||
return getCellVirtualRect(cell.x,cell.y);
|
||||
}
|
||||
|
||||
Rectangle getCellVirtualRect(int x, int y) {
|
||||
x=fCellWidth*x;
|
||||
y=fCellHeight*y;
|
||||
return new Rectangle(x,y,fCellWidth,fCellHeight);
|
||||
}
|
||||
protected void viewRectangleChanged(int x, int y, int width, int height) {
|
||||
int cellX=virtualXToCell(x);
|
||||
int cellY=virtualYToCell(y);
|
||||
// End coordinates
|
||||
int xE=virtualXToCell(x+fCellWidth+width-1);
|
||||
if(xE>getCols())
|
||||
xE=getCols();
|
||||
int yE=virtualYToCell(y+fCellHeight+height-1);
|
||||
if(yE>getRows())
|
||||
yE=getRows();
|
||||
visibleCellRectangleChanged(cellX,cellY,xE-cellX,yE-cellY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the viewed part has changed.
|
||||
* Override when you need this information....
|
||||
* Is only called if the values change (well, almost)
|
||||
* @param x origin of visible cells
|
||||
* @param y
|
||||
* @param width number of cells visible in x direction
|
||||
* @param height
|
||||
*/
|
||||
protected void visibleCellRectangleChanged(int x, int y, int width, int height) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public interface ILinelRenderer {
|
||||
int getCellWidth();
|
||||
int getCellHeight();
|
||||
void drawLine(ITextCanvasModel model, GC gc, int line, int x, int y, int colFirst, int colLast);
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
|
||||
public interface ITextCanvasModel {
|
||||
void addCellCanvasModelListener(ITextCanvasModelListener listener);
|
||||
void removeCellCanvasModelListener(ITextCanvasModelListener listener);
|
||||
|
||||
ITerminalTextDataReadOnly getTerminalText();
|
||||
/**
|
||||
* This is is
|
||||
* @param startLine
|
||||
* @param startCol
|
||||
* @param height
|
||||
* @param width
|
||||
*/
|
||||
void setVisibleRectangle(int startLine, int startCol, int height, int width);
|
||||
|
||||
/**
|
||||
* @return true when the cursor is shown (used for blinking cursors)
|
||||
*/
|
||||
boolean isCursorOn();
|
||||
/**
|
||||
* Show/Hide the cursor.
|
||||
* @param visible
|
||||
*/
|
||||
void setCursorEnabled(boolean visible);
|
||||
|
||||
/**
|
||||
* @return true if the cursor is shown.
|
||||
*/
|
||||
boolean isCursorEnabled();
|
||||
|
||||
/**
|
||||
* @return the line of the cursor
|
||||
*/
|
||||
int getCursorLine();
|
||||
/**
|
||||
* @return the column of the cursor
|
||||
*/
|
||||
int getCursorColumn();
|
||||
|
||||
/**
|
||||
* @return the start of the selection or null if nothing is selected
|
||||
* {@link Point#x} is the column and {@link Point#y} is the line.
|
||||
*/
|
||||
Point getSelectionStart();
|
||||
/**
|
||||
* @return the end of the selection or null if nothing is selected
|
||||
* {@link Point#x} is the column and {@link Point#y} is the line.
|
||||
*/
|
||||
Point getSelectionEnd();
|
||||
/**
|
||||
* @param startLine
|
||||
* @param endLine
|
||||
* @param startColumn
|
||||
* @param endColumn
|
||||
*/
|
||||
void setSelection(int startLine, int endLine, int startColumn, int endColumn);
|
||||
|
||||
/**
|
||||
* @param line
|
||||
* @return true if line is part of the selection
|
||||
*/
|
||||
boolean hasLineSelection(int line);
|
||||
|
||||
String getSelectedText();
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
/**
|
||||
*/
|
||||
public interface ITextCanvasModelListener {
|
||||
void cellSizeChanged();
|
||||
void rangeChanged(int col, int line, int width, int height);
|
||||
void dimensionsChanged(int cols, int rows);
|
||||
/**
|
||||
* Called when any text change happened. Used to scroll to the
|
||||
* end of text in auto scroll mode. This does not get fired
|
||||
* when the window of interest has changed!
|
||||
*/
|
||||
void terminalDataChanged();
|
||||
}
|
|
@ -0,0 +1,305 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 1996, 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
* Douglas Lea (Addison Wesley) - [cq:1552] BoundedBufferWithStateTracking adapted to BoundedByteBuffer
|
||||
* Martin Oberhuber (Wind River) - the waitForAvailable method
|
||||
*******************************************************************************/
|
||||
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
/**
|
||||
* The main purpose of this class is to start a runnable in the
|
||||
* display thread when data is available and to pretend no data
|
||||
* is available after a given amount of time the runnable is running.
|
||||
*
|
||||
*/
|
||||
public class PipedInputStream extends InputStream {
|
||||
/**
|
||||
* The output stream used by the terminal backend to write to the terminal
|
||||
*/
|
||||
protected final OutputStream fOutputStream;
|
||||
/**
|
||||
* A blocking byte queue.
|
||||
*/
|
||||
private final BoundedByteBuffer fQueue;
|
||||
|
||||
/**
|
||||
* A byte bounded buffer used to synchronize the input and the output stream.
|
||||
* <p>
|
||||
* Adapted from BoundedBufferWithStateTracking
|
||||
* http://gee.cs.oswego.edu/dl/cpj/allcode.java
|
||||
* http://gee.cs.oswego.edu/dl/cpj/
|
||||
* <p>
|
||||
* BoundedBufferWithStateTracking is part of the examples for the book
|
||||
* Concurrent Programming in Java: Design Principles and Patterns by
|
||||
* Doug Lea (ISBN 0-201-31009-0). Second edition published by
|
||||
* Addison-Wesley, November 1999. The code is
|
||||
* Copyright(c) Douglas Lea 1996, 1999 and released to the public domain
|
||||
* and may be used for any purposes whatsoever.
|
||||
* <p>
|
||||
* For some reasons a solution based on
|
||||
* PipedOutputStream/PipedIntputStream
|
||||
* does work *very* slowly:
|
||||
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4404700
|
||||
* <p>
|
||||
*
|
||||
*/
|
||||
private class BoundedByteBuffer {
|
||||
protected final byte[] fBuffer; // the elements
|
||||
protected int fPutPos = 0; // circular indices
|
||||
protected int fTakePos = 0;
|
||||
protected int fUsedSlots = 0; // the count
|
||||
private boolean fClosed;
|
||||
public BoundedByteBuffer(int capacity) throws IllegalArgumentException {
|
||||
// make sure we don't deadlock on too small capacity
|
||||
if (capacity <= 0)
|
||||
throw new IllegalArgumentException();
|
||||
fBuffer = new byte[capacity];
|
||||
}
|
||||
/**
|
||||
* @return the bytes available for {@link #read()}
|
||||
* Must be called with a lock on this!
|
||||
*/
|
||||
public int available() {
|
||||
return fUsedSlots;
|
||||
}
|
||||
/**
|
||||
* Writes a single byte to the buffer. Blocks if the buffer is full.
|
||||
* @param b
|
||||
* @throws InterruptedException
|
||||
* Must be called with a lock on this!
|
||||
*/
|
||||
public void write(byte b) throws InterruptedException {
|
||||
while (fUsedSlots == fBuffer.length)
|
||||
// wait until not full
|
||||
wait();
|
||||
|
||||
fBuffer[fPutPos] = b;
|
||||
fPutPos = (fPutPos + 1) % fBuffer.length; // cyclically increment
|
||||
|
||||
if (fUsedSlots++ == 0) // signal if was empty
|
||||
notifyAll();
|
||||
}
|
||||
public int getFreeSlots() {
|
||||
return fBuffer.length - fUsedSlots;
|
||||
}
|
||||
public void write(byte[] b, int off, int len) throws InterruptedException {
|
||||
assert len<=getFreeSlots();
|
||||
while (fUsedSlots == fBuffer.length)
|
||||
// wait until not full
|
||||
wait();
|
||||
int n = Math.min(len, fBuffer.length - fPutPos);
|
||||
System.arraycopy(b, off, fBuffer, fPutPos, n);
|
||||
if (fPutPos + len > n)
|
||||
System.arraycopy(b, off + n, fBuffer, 0, len - n);
|
||||
fPutPos = (fPutPos + len) % fBuffer.length; // cyclically increment
|
||||
boolean wasEmpty = fUsedSlots == 0;
|
||||
fUsedSlots += len;
|
||||
if (wasEmpty) // signal if was empty
|
||||
notifyAll();
|
||||
}
|
||||
/**
|
||||
* Read a single byte. Blocks until a byte is available.
|
||||
* @return a byte from the buffer
|
||||
* @throws InterruptedException
|
||||
* Must be called with a lock on this!
|
||||
*/
|
||||
public int read() throws InterruptedException {
|
||||
while (fUsedSlots == 0) {
|
||||
if(fClosed)
|
||||
return -1;
|
||||
// wait until not empty
|
||||
wait();
|
||||
}
|
||||
byte b = fBuffer[fTakePos];
|
||||
fTakePos = (fTakePos + 1) % fBuffer.length;
|
||||
|
||||
if (fUsedSlots-- == fBuffer.length) // signal if was full
|
||||
notifyAll();
|
||||
return b;
|
||||
}
|
||||
public int read(byte[] cbuf, int off, int len) throws InterruptedException {
|
||||
assert len<=available();
|
||||
while (fUsedSlots == 0) {
|
||||
if(fClosed)
|
||||
return 0;
|
||||
// wait until not empty
|
||||
wait();
|
||||
}
|
||||
int n = Math.min(len, fBuffer.length - fTakePos);
|
||||
System.arraycopy(fBuffer, fTakePos, cbuf, off, n);
|
||||
if (fTakePos + len > n)
|
||||
System.arraycopy(fBuffer, 0, cbuf, off + n, len - n);
|
||||
fTakePos = (fTakePos + len) % fBuffer.length;
|
||||
boolean wasFull = fUsedSlots == fBuffer.length;
|
||||
fUsedSlots -= len;
|
||||
if(wasFull)
|
||||
notifyAll();
|
||||
|
||||
return len;
|
||||
}
|
||||
public void close() {
|
||||
fClosed=true;
|
||||
notifyAll();
|
||||
}
|
||||
public boolean isClosed() {
|
||||
return fClosed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An output stream that calls {@link PipedInputStream#textAvailable}
|
||||
* every time data is written to the stream. The data is written to
|
||||
* {@link PipedInputStream#fQueue}.
|
||||
*
|
||||
*/
|
||||
class PipedOutputStream extends OutputStream {
|
||||
public void write(byte[] b, int off, int len) throws IOException {
|
||||
try {
|
||||
synchronized (fQueue) {
|
||||
if(fQueue.isClosed())
|
||||
throw new IOException("Stream is closed!"); //$NON-NLS-1$
|
||||
int written=0;
|
||||
while(written<len) {
|
||||
if(fQueue.getFreeSlots()==0) {
|
||||
// if no slots available, write one byte and block
|
||||
// until free slots are available
|
||||
fQueue.write(b[off + written]);
|
||||
written++;
|
||||
} else {
|
||||
// if slots are available, write as much as
|
||||
// we can in one junk
|
||||
int n=Math.min(fQueue.getFreeSlots(), len-written);
|
||||
fQueue.write(b, off + written, n);
|
||||
written+=n;
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
public void write(int b) throws IOException {
|
||||
try {
|
||||
synchronized(fQueue) {
|
||||
if(fQueue.isClosed())
|
||||
throw new IOException("Stream is closed!"); //$NON-NLS-1$
|
||||
fQueue.write((byte)b);
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
public void close() throws IOException {
|
||||
synchronized(fQueue) {
|
||||
fQueue.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param bufferSize the size of the buffer of the output stream
|
||||
*/
|
||||
public PipedInputStream(int bufferSize) {
|
||||
fOutputStream =new PipedOutputStream();
|
||||
fQueue=new BoundedByteBuffer(bufferSize);
|
||||
}
|
||||
/**
|
||||
* @return the output stream used by the backend to write to the terminal.
|
||||
*/
|
||||
public OutputStream getOutputStream() {
|
||||
return fOutputStream;
|
||||
}
|
||||
/**
|
||||
* Waits until data is available for reading.
|
||||
* @param millis see {@link Object#wait(long)}
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public void waitForAvailable(long millis) throws InterruptedException {
|
||||
synchronized(fQueue) {
|
||||
if(fQueue.available()==0)
|
||||
fQueue.wait(millis);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Must be called in the Display Thread!
|
||||
* @return true if a character is available for the terminal to show.
|
||||
*/
|
||||
public int available() {
|
||||
synchronized(fQueue) {
|
||||
return fQueue.available();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return the next available byte. Check with {@link #available}
|
||||
* if characters are available.
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
try {
|
||||
synchronized (fQueue) {
|
||||
return fQueue.read();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Closing a <tt>PipedInputStream</tt> has no effect. The methods in
|
||||
* this class can be called after the stream has been closed without
|
||||
* generating an <tt>IOException</tt>.
|
||||
* <p>
|
||||
*/
|
||||
public void close() throws IOException {
|
||||
}
|
||||
|
||||
public int read(byte[] cbuf, int off, int len) throws IOException {
|
||||
int n=0;
|
||||
if(len==0)
|
||||
return 0;
|
||||
// read as much as we can using a single synchronized statement
|
||||
try {
|
||||
synchronized (fQueue) {
|
||||
// if nothing available, block and read one byte
|
||||
if (fQueue.available() == 0) {
|
||||
// block now until at least one byte is available
|
||||
int c = fQueue.read();
|
||||
// are we at the end of stream
|
||||
if (c == -1)
|
||||
return -1;
|
||||
cbuf[off] = (byte) c;
|
||||
n++;
|
||||
}
|
||||
// is there more data available?
|
||||
if (n < len && fQueue.available() > 0) {
|
||||
// read at most available()
|
||||
int nn = Math.min(fQueue.available(), len - n);
|
||||
// are we at the end of the stream?
|
||||
if (nn == 0 && fQueue.isClosed()) {
|
||||
// if no byte was read, return -1 to indicate end of stream
|
||||
// else return the bytes we read up to now
|
||||
if (n == 0)
|
||||
n = -1;
|
||||
return n;
|
||||
}
|
||||
fQueue.read(cbuf, off + n, nn);
|
||||
n += nn;
|
||||
}
|
||||
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot;
|
||||
|
||||
/**
|
||||
* @author Michael.Scharf@scharf-software.com
|
||||
*
|
||||
*/
|
||||
public class PollingTextCanvasModel extends AbstractTextCanvasModel {
|
||||
int fPollInterval=50;
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public PollingTextCanvasModel(ITerminalTextDataSnapshot snapshot) {
|
||||
super(snapshot);
|
||||
Display.getDefault().timerExec(fPollInterval,new Runnable(){
|
||||
public void run() {
|
||||
update();
|
||||
Display.getDefault().timerExec(fPollInterval,this);
|
||||
}});
|
||||
}
|
||||
public void setUpdateInterval(int t) {
|
||||
fPollInterval=t;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.eclipse.jface.resource.JFaceResources;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
import org.eclipse.tm.terminal.model.StyleColor;
|
||||
|
||||
public class StyleMap {
|
||||
String fFontName=JFaceResources.TEXT_FONT;
|
||||
Map fColorMap=new HashMap();
|
||||
Map fFontMap=new HashMap();
|
||||
private Point fCharSize;
|
||||
private Style fDefaultStyle;
|
||||
StyleMap() {
|
||||
Display display=Display.getCurrent();
|
||||
fColorMap.put(StyleColor.getStyleColor("white"), new Color(display,255,255,255)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("black"), new Color(display,0,0,0)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("red"), new Color(display,255,128,128)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("green"), new Color(display,128,255,128)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("blue"), new Color(display,128,128,255)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("yellow"), new Color(display,255,255,0)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("cyan"), new Color(display,0,255,255)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("magenta"), new Color(display,255,255,0)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("gray"), new Color(display,128,128,128)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("WHITE"), new Color(display,255,255,255)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("BLACK"), new Color(display,0,0,0)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("RED"), new Color(display,255,128,128)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("GREEN"), new Color(display,128,255,128)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("BLUE"), new Color(display,128,128,255)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("YELLOW"), new Color(display,255,255,0)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("CYAN"), new Color(display,0,255,255)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("MAGENTA"), new Color(display,255,255,0)); //$NON-NLS-1$
|
||||
fColorMap.put(StyleColor.getStyleColor("GRAY"), new Color(display,128,128,128)); //$NON-NLS-1$
|
||||
fDefaultStyle=Style.getStyle(StyleColor.getStyleColor("black"),StyleColor.getStyleColor("white")); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
GC gc = new GC (display);
|
||||
gc.setFont(getFont());
|
||||
fCharSize = gc.textExtent ("W"); //$NON-NLS-1$
|
||||
gc.dispose ();
|
||||
|
||||
}
|
||||
public Color getColor(StyleColor colorName) {
|
||||
return (Color) fColorMap.get(colorName);
|
||||
}
|
||||
public Color getForegrondColor(Style style) {
|
||||
style = defaultIfNull(style);
|
||||
if(style.isReverse())
|
||||
return getColor(style.getBackground());
|
||||
else
|
||||
return getColor(style.getForground());
|
||||
}
|
||||
private Style defaultIfNull(Style style) {
|
||||
if(style==null)
|
||||
style=fDefaultStyle;
|
||||
return style;
|
||||
}
|
||||
public Color getBackgroundColor(Style style) {
|
||||
style = defaultIfNull(style);
|
||||
if(style.isReverse())
|
||||
return getColor(style.getForground());
|
||||
else
|
||||
return getColor(style.getBackground());
|
||||
}
|
||||
// static Font getBoldFont(Font font) {
|
||||
// FontData fontDatas[] = font.getFontData();
|
||||
// FontData data = fontDatas[0];
|
||||
// return new Font(Display.getCurrent(), data.getName(), data.getHeight(), data.getStyle()|SWT.BOLD);
|
||||
// }
|
||||
|
||||
public Font getFont(Style style) {
|
||||
style = defaultIfNull(style);
|
||||
if(style.isBold()) {
|
||||
return JFaceResources.getFontRegistry().getBold(fFontName);
|
||||
} else if(style.isUnderline()) {
|
||||
return JFaceResources.getFontRegistry().getItalic(fFontName);
|
||||
|
||||
}
|
||||
return JFaceResources.getFontRegistry().get(fFontName);
|
||||
}
|
||||
|
||||
public Font getFont() {
|
||||
return JFaceResources.getFontRegistry().get(fFontName);
|
||||
|
||||
}
|
||||
public int getFontWidth() {
|
||||
return fCharSize.x;
|
||||
}
|
||||
public int getFontHeight() {
|
||||
return fCharSize.y;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.dnd.Clipboard;
|
||||
import org.eclipse.swt.dnd.TextTransfer;
|
||||
import org.eclipse.swt.dnd.Transfer;
|
||||
import org.eclipse.swt.events.FocusEvent;
|
||||
import org.eclipse.swt.events.FocusListener;
|
||||
import org.eclipse.swt.events.MouseEvent;
|
||||
import org.eclipse.swt.events.MouseListener;
|
||||
import org.eclipse.swt.events.MouseMoveListener;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
|
||||
/**
|
||||
* A cell oriented Canvas. Maintains a list of "cells".
|
||||
* It can either be vertically or horizontally scrolled.
|
||||
* The CellRenderer is responsible for painting the cell.
|
||||
*/
|
||||
public class TextCanvas extends GridCanvas {
|
||||
protected final ITextCanvasModel fCellCanvasModel;
|
||||
/** Renders the cells */
|
||||
private ILinelRenderer fCellRenderer;
|
||||
private boolean fScrollLock;
|
||||
private Point fDraggingStart;
|
||||
private Point fDraggingEnd;
|
||||
/**
|
||||
* Create a new CellCanvas with the given SWT style bits.
|
||||
* (SWT.H_SCROLL and SWT.V_SCROLL are automatically added).
|
||||
*/
|
||||
public TextCanvas(Composite parent, ITextCanvasModel model, int style) {
|
||||
super(parent, style | SWT.H_SCROLL | SWT.V_SCROLL);
|
||||
fCellCanvasModel=model;
|
||||
fCellCanvasModel.addCellCanvasModelListener(new ITextCanvasModelListener(){
|
||||
public void cellSizeChanged() {
|
||||
setCellWidth(fCellRenderer.getCellWidth());
|
||||
setCellHeight(fCellRenderer.getCellHeight());
|
||||
|
||||
calculateGrid();
|
||||
|
||||
}
|
||||
public void rangeChanged(int col, int line, int width, int height) {
|
||||
repaintRange(col,line,width,height);
|
||||
}
|
||||
public void dimensionsChanged(int cols, int rows) {
|
||||
calculateGrid();
|
||||
}
|
||||
public void terminalDataChanged() {
|
||||
if(isDisposed())
|
||||
return;
|
||||
scrollToEnd();
|
||||
}
|
||||
});
|
||||
addListener(SWT.Resize, new Listener() {
|
||||
public void handleEvent(Event e) {
|
||||
calculateGrid();
|
||||
}
|
||||
});
|
||||
addFocusListener(new FocusListener(){
|
||||
public void focusGained(FocusEvent e) {
|
||||
fCellCanvasModel.setCursorEnabled(true);
|
||||
}
|
||||
public void focusLost(FocusEvent e) {
|
||||
fCellCanvasModel.setCursorEnabled(false);
|
||||
}});
|
||||
addMouseListener(new MouseListener(){
|
||||
public void mouseDoubleClick(MouseEvent e) {
|
||||
}
|
||||
public void mouseDown(MouseEvent e) {
|
||||
if(e.button==1) { // left button
|
||||
fDraggingStart=screenPointToCell(e.x, e.y);
|
||||
fDraggingEnd=null;
|
||||
}
|
||||
}
|
||||
public void mouseUp(MouseEvent e) {
|
||||
if(e.button==1) { // left button
|
||||
setSelection(screenPointToCell(e.x, e.y));
|
||||
fDraggingStart=null;
|
||||
}
|
||||
}
|
||||
});
|
||||
addMouseMoveListener(new MouseMoveListener() {
|
||||
|
||||
public void mouseMove(MouseEvent e) {
|
||||
if (fDraggingStart != null) {
|
||||
setSelection(screenPointToCell(e.x, e.y));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void setSelection(Point p) {
|
||||
if (!p.equals(fDraggingEnd)) {
|
||||
fDraggingEnd = p;
|
||||
if (compare(p, fDraggingStart) < 0) {
|
||||
fCellCanvasModel.setSelection(p.y, fDraggingStart.y, p.x, fDraggingStart.x);
|
||||
} else {
|
||||
fCellCanvasModel.setSelection(fDraggingStart.y, p.y, fDraggingStart.x, p.x);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int compare(Point p1, Point p2) {
|
||||
if (p1.equals(p2))
|
||||
return 0;
|
||||
if (p1.y == p2.y) {
|
||||
if (p1.x > p2.x)
|
||||
return 1;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
if (p1.y > p2.y) {
|
||||
return 1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public void setCellRenderer(ILinelRenderer cellRenderer) {
|
||||
fCellRenderer = cellRenderer;
|
||||
setCellWidth(fCellRenderer.getCellWidth());
|
||||
setCellHeight(fCellRenderer.getCellHeight());
|
||||
}
|
||||
public ILinelRenderer getCellRenderer() {
|
||||
return fCellRenderer;
|
||||
}
|
||||
private void calculateGrid() {
|
||||
setVirtualExtend(getCols()*getCellWidth(),getRows()*getCellHeight());
|
||||
// scroll to end
|
||||
scrollToEnd();
|
||||
// make sure the scroll area is correct:
|
||||
scrollY(getVerticalBar());
|
||||
scrollX(getHorizontalBar());
|
||||
|
||||
updateViewRectangle();
|
||||
getParent().layout();
|
||||
redraw();
|
||||
}
|
||||
void scrollToEnd() {
|
||||
if(!fScrollLock) {
|
||||
int y=-(getRows()*getCellHeight()-getClientArea().height);
|
||||
Rectangle v=getViewRectangle();
|
||||
if(v.y!=y) {
|
||||
setVirtualOrigin(0,y);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @return true if the cursor should be shown on output....
|
||||
*/
|
||||
public boolean isScrollLock() {
|
||||
return fScrollLock;
|
||||
}
|
||||
/**
|
||||
* If set then if the size changes
|
||||
* @param scrollLock
|
||||
*/
|
||||
public void setScrollLock(boolean scrollLock) {
|
||||
fScrollLock=scrollLock;
|
||||
}
|
||||
protected void repaintRange(int col, int line, int width, int height) {
|
||||
Point origin=cellToOriginOnScreen(col,line);
|
||||
Rectangle r=new Rectangle(origin.x,origin.y,width*getCellWidth(),height*getCellHeight());
|
||||
repaint(r);
|
||||
}
|
||||
protected void drawLine(GC gc, int line, int x, int y, int colFirst, int colLast) {
|
||||
fCellRenderer.drawLine(fCellCanvasModel, gc,line,x,y,colFirst, colLast);
|
||||
|
||||
}
|
||||
protected void visibleCellRectangleChanged(int x, int y, int width, int height) {
|
||||
fCellCanvasModel.setVisibleRectangle(y,x,height,width);
|
||||
update();
|
||||
}
|
||||
protected int getCols() {
|
||||
return fCellCanvasModel.getTerminalText().getWidth();
|
||||
}
|
||||
protected int getRows() {
|
||||
return fCellCanvasModel.getTerminalText().getHeight();
|
||||
}
|
||||
public String getSelectionText() {
|
||||
// TODO -- create a hasSelectionMethod!
|
||||
return fCellCanvasModel.getSelectedText();
|
||||
}
|
||||
public void copy() {
|
||||
Clipboard clipboard = new Clipboard(getDisplay());
|
||||
clipboard.setContents(new Object[] { getSelectionText() }, new Transfer[] { TextTransfer.getInstance() });
|
||||
clipboard.dispose();
|
||||
}
|
||||
public void selectAll() {
|
||||
fCellCanvasModel.setSelection(0, fCellCanvasModel.getTerminalText().getHeight(), 0, fCellCanvasModel.getTerminalText().getWidth());
|
||||
|
||||
}
|
||||
public boolean isEmpty() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,141 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.Font;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.widgets.Display;
|
||||
import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly;
|
||||
import org.eclipse.tm.terminal.model.LineSegment;
|
||||
import org.eclipse.tm.terminal.model.Style;
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public class TextLineRenderer implements ILinelRenderer {
|
||||
TextCanvas fCanvas;
|
||||
private final ITextCanvasModel fModel;
|
||||
StyleMap fStyleMap=new StyleMap();
|
||||
Color fBackgroundColor;
|
||||
public TextLineRenderer(TextCanvas c, ITextCanvasModel model) {
|
||||
fCanvas=c;
|
||||
fModel=model;
|
||||
fBackgroundColor=c.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see com.imagicus.thumbs.view.ICellRenderer#getCellWidth()
|
||||
*/
|
||||
public int getCellWidth() {
|
||||
return fStyleMap.getFontWidth();
|
||||
}
|
||||
/* (non-Javadoc)
|
||||
* @see com.imagicus.thumbs.view.ICellRenderer#getCellHeight()
|
||||
*/
|
||||
public int getCellHeight() {
|
||||
return fStyleMap.getFontHeight();
|
||||
}
|
||||
public void drawLine(ITextCanvasModel model, GC gc, int line, int x, int y, int colFirst, int colLast) {
|
||||
if(line<0 || line>=getTerminalText().getHeight() || colFirst>=getTerminalText().getWidth() || colFirst-colLast==0) {
|
||||
fillBackground(gc, x, y, getCellWidth()*(colFirst-colLast), getCellHeight());
|
||||
} else {
|
||||
colLast=Math.min(colLast, getTerminalText().getWidth());
|
||||
LineSegment[] segments=getTerminalText().getLineSegments(line, colFirst, colLast-colFirst);
|
||||
for (int i = 0; i < segments.length; i++) {
|
||||
LineSegment segment=segments[i];
|
||||
Style style=segment.getStyle();
|
||||
setupGC(gc, style);
|
||||
String text=segment.getText();
|
||||
drawText(gc, x, y, colFirst, segment.getColumn(), text);
|
||||
drawCursor(model, gc, line, x, y, colFirst);
|
||||
}
|
||||
if(fModel.hasLineSelection(line)) {
|
||||
gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT));
|
||||
gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION));
|
||||
Point start=model.getSelectionStart();
|
||||
Point end=model.getSelectionEnd();
|
||||
char[] chars=model.getTerminalText().getChars(line);
|
||||
if(chars==null)
|
||||
return;
|
||||
int offset=0;
|
||||
if(start.y==line)
|
||||
offset=start.x;
|
||||
offset=Math.max(offset, colFirst);
|
||||
int len;
|
||||
if(end.y==line)
|
||||
len=end.x-offset+1;
|
||||
else
|
||||
len=chars.length-offset+1;
|
||||
len=Math.min(len,chars.length-offset);
|
||||
if(len>0) {
|
||||
String text=new String(chars,offset,len);
|
||||
drawText(gc, x, y, colFirst, offset, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void fillBackground(GC gc, int x, int y, int width, int height) {
|
||||
Color bg=gc.getBackground();
|
||||
gc.setBackground(getBackgroundColor());
|
||||
gc.fillRectangle (x,y,width,height);
|
||||
gc.setBackground(bg);
|
||||
|
||||
}
|
||||
|
||||
private Color getBackgroundColor() {
|
||||
return fBackgroundColor;
|
||||
}
|
||||
private void drawCursor(ITextCanvasModel model, GC gc, int row, int x, int y, int colFirst) {
|
||||
if(!model.isCursorOn())
|
||||
return;
|
||||
int cursorLine=model.getCursorLine();
|
||||
|
||||
if(row==cursorLine) {
|
||||
int cursorColumn=model.getCursorColumn();
|
||||
if(cursorColumn<getTerminalText().getWidth()) {
|
||||
Style style=getTerminalText().getStyle(row, cursorColumn);
|
||||
if(style==null) {
|
||||
// TODO make the cursor color customizable
|
||||
style=Style.getStyle("BLACK", "WHITE"); //$NON-NLS-1$//$NON-NLS-2$
|
||||
}
|
||||
style=style.setReverse(!style.isReverse());
|
||||
setupGC(gc,style);
|
||||
String text=String.valueOf(getTerminalText().getChar(row, cursorColumn));
|
||||
drawText(gc, x, y, colFirst, cursorColumn, text);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void drawText(GC gc, int x, int y, int colFirst, int col, String text) {
|
||||
int offset=(col-colFirst)*getCellWidth();
|
||||
text=text.replace('\000', ' ');
|
||||
gc.drawString(text,x+offset,y,false);
|
||||
}
|
||||
private void setupGC(GC gc, Style style) {
|
||||
Color c=fStyleMap.getForegrondColor(style);
|
||||
if(c!=gc.getForeground()) {
|
||||
gc.setForeground(c);
|
||||
}
|
||||
c=fStyleMap.getBackgroundColor(style);
|
||||
if(c!=gc.getBackground()) {
|
||||
gc.setBackground(c);
|
||||
}
|
||||
Font f=fStyleMap.getFont(style);
|
||||
if(f!=gc.getFont()) {
|
||||
gc.setFont(f);
|
||||
}
|
||||
}
|
||||
ITerminalTextDataReadOnly getTerminalText() {
|
||||
return fModel.getTerminalText();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,353 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.internal.terminal.textcanvas;
|
||||
|
||||
|
||||
import org.eclipse.swt.SWT;
|
||||
import org.eclipse.swt.events.DisposeEvent;
|
||||
import org.eclipse.swt.events.DisposeListener;
|
||||
import org.eclipse.swt.graphics.Color;
|
||||
import org.eclipse.swt.graphics.GC;
|
||||
import org.eclipse.swt.graphics.Point;
|
||||
import org.eclipse.swt.graphics.Rectangle;
|
||||
import org.eclipse.swt.widgets.Canvas;
|
||||
import org.eclipse.swt.widgets.Composite;
|
||||
import org.eclipse.swt.widgets.Event;
|
||||
import org.eclipse.swt.widgets.Listener;
|
||||
import org.eclipse.swt.widgets.ScrollBar;
|
||||
|
||||
/**
|
||||
* A <code>Canvas</code> showing a virtual object.
|
||||
* Virtual: the extent of the total canvas.
|
||||
* Screen: the visible client area in the screen.
|
||||
*/
|
||||
public abstract class VirtualCanvas extends Canvas {
|
||||
|
||||
private Rectangle fVirtualBounds = new Rectangle(0,0,0,0);
|
||||
private Rectangle fClientArea;
|
||||
private GC fPaintGC=null;
|
||||
/**
|
||||
* prevent infinite loop in {@link #updateScrollbars()}
|
||||
*/
|
||||
private boolean fInUpdateScrollbars;
|
||||
|
||||
public VirtualCanvas(Composite parent, int style) {
|
||||
super(parent, style|SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE);
|
||||
fPaintGC= new GC(this);
|
||||
fClientArea=getClientArea();
|
||||
addListener(SWT.Paint, new Listener() {
|
||||
public void handleEvent(Event event) {
|
||||
paint(event.gc);
|
||||
}
|
||||
});
|
||||
addListener(SWT.Resize, new Listener() {
|
||||
public void handleEvent(Event event) {
|
||||
fClientArea=getClientArea();
|
||||
updateViewRectangle();
|
||||
}
|
||||
});
|
||||
getVerticalBar().addListener(SWT.Selection, new Listener() {
|
||||
public void handleEvent(Event e) {
|
||||
scrollY((ScrollBar)e.widget);
|
||||
postScrollEventHandling(e);
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
getHorizontalBar().addListener(SWT.Selection, new Listener() {
|
||||
public void handleEvent(Event e) {
|
||||
scrollX((ScrollBar)e.widget);
|
||||
postScrollEventHandling(e);
|
||||
|
||||
}
|
||||
});
|
||||
addDisposeListener(new DisposeListener(){
|
||||
public void widgetDisposed(DisposeEvent e) {
|
||||
if(fPaintGC!=null){
|
||||
fPaintGC.dispose();
|
||||
fPaintGC=null;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
/** HACK: run an event loop if the scrollbar is dragged...*/
|
||||
private void postScrollEventHandling(Event e) {
|
||||
if(true&&e.detail==SWT.DRAG) {
|
||||
// TODO check if this is always ok???
|
||||
// used to process runnables while scrolling
|
||||
// This fixes the update problems when scrolling!
|
||||
// see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=47582#5
|
||||
// TODO investigate:
|
||||
// The alternative is to call redraw on the new visible area
|
||||
// redraw(expose.x, expose.y, expose.width, expose.height, true);
|
||||
|
||||
while (!getDisplay().isDisposed() && getDisplay().readAndDispatch()) {
|
||||
// do nothing here...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void scrollX(ScrollBar hBar) {
|
||||
int hSelection = hBar.getSelection ();
|
||||
int destX = -hSelection - fVirtualBounds.x;
|
||||
fVirtualBounds.x = -hSelection;
|
||||
scrollSmart(destX, 0);
|
||||
updateViewRectangle();
|
||||
}
|
||||
protected void scrollXDelta(int delta) {
|
||||
getHorizontalBar().setSelection(-fVirtualBounds.x+delta);
|
||||
scrollX(getHorizontalBar());
|
||||
}
|
||||
|
||||
protected void scrollY(ScrollBar vBar) {
|
||||
int vSelection = vBar.getSelection ();
|
||||
int destY = -vSelection - fVirtualBounds.y;
|
||||
if(destY!=0) {
|
||||
fVirtualBounds.y = -vSelection;
|
||||
scrollSmart(0,destY);
|
||||
updateViewRectangle();
|
||||
}
|
||||
|
||||
}
|
||||
protected void scrollYDelta(int delta) {
|
||||
getVerticalBar().setSelection(-fVirtualBounds.y+delta);
|
||||
scrollY(getVerticalBar());
|
||||
}
|
||||
|
||||
|
||||
private void scrollSmart(int deltaX, int deltaY) {
|
||||
Rectangle rect = getBounds();
|
||||
scroll (deltaX, deltaY, 0, 0, rect.width, rect.height, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param rect in virtual space
|
||||
*/
|
||||
protected void revealRect(Rectangle rect) {
|
||||
Rectangle visibleRect=getScreenRectInVirtualSpace();
|
||||
// scroll the X part
|
||||
int deltaX=0;
|
||||
if(rect.x<visibleRect.x) {
|
||||
deltaX=rect.x-visibleRect.x;
|
||||
} else if(visibleRect.x+visibleRect.width<rect.x+rect.width){
|
||||
deltaX=(rect.x+rect.width)-(visibleRect.x+visibleRect.width);
|
||||
}
|
||||
if(deltaX!=0) {
|
||||
getHorizontalBar().setSelection(-fVirtualBounds.x+deltaX);
|
||||
scrollX(getHorizontalBar());
|
||||
}
|
||||
|
||||
// scroll the Y part
|
||||
int deltaY=0;
|
||||
if(rect.y<visibleRect.y){
|
||||
deltaY=rect.y-visibleRect.y;
|
||||
} else if(visibleRect.y+visibleRect.height<rect.y+rect.height){
|
||||
deltaY=(rect.y+rect.height)-(visibleRect.y+visibleRect.height);
|
||||
|
||||
}
|
||||
if(deltaY!=0) {
|
||||
getVerticalBar().setSelection(-fVirtualBounds.y+deltaY);
|
||||
scrollY(getVerticalBar());
|
||||
}
|
||||
}
|
||||
|
||||
protected void repaint(Rectangle r) {
|
||||
if (fPaintGC!=null) {
|
||||
if(inClipping(r,fClientArea)) {
|
||||
fPaintGC.setClipping(r);
|
||||
paint(fPaintGC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param gc
|
||||
*/
|
||||
abstract protected void paint(GC gc);
|
||||
protected Color getBackgroundColor() {
|
||||
// return getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
|
||||
return getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND);
|
||||
}
|
||||
protected void paintUnoccupiedSpace(GC gc, Rectangle clipping) {
|
||||
int width=fVirtualBounds.width;
|
||||
int height=fVirtualBounds.height;
|
||||
int marginWidth = (clipping.x+clipping.width) - width;
|
||||
int marginHeight = (clipping.y+clipping.height) - height;
|
||||
if(marginWidth>0||marginHeight>0){
|
||||
Color bg=getBackground();
|
||||
gc.setBackground(getBackgroundColor());
|
||||
if (marginWidth > 0) {
|
||||
gc.fillRectangle (width, clipping.y, marginWidth, clipping.height);
|
||||
}
|
||||
if (marginHeight > 0) {
|
||||
gc.fillRectangle (clipping.x, height, clipping.width, marginHeight);
|
||||
}
|
||||
gc.setBackground(bg);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
protected boolean inClipping(Rectangle clipping, Rectangle r) {
|
||||
// TODO check if this is OK in all cases (the <=!)
|
||||
//
|
||||
if(r.x+r.width<=clipping.x)
|
||||
return false;
|
||||
if(clipping.x+clipping.width<=r.x)
|
||||
return false;
|
||||
if(r.y+r.height<=clipping.y)
|
||||
return false;
|
||||
if(clipping.y+clipping.height<=r.y)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
/**
|
||||
* @return the screen rect in virtual space (starting with (0,0))
|
||||
* of the visible screen. (x,y>=0)
|
||||
*/
|
||||
protected Rectangle getScreenRectInVirtualSpace() {
|
||||
Rectangle r= new Rectangle(fClientArea.x-fVirtualBounds.x,fClientArea.y-fVirtualBounds.y,fClientArea.width,fClientArea.height);
|
||||
return r;
|
||||
}
|
||||
/**
|
||||
* @return the rect in virtual space (starting with (0,0))
|
||||
* of the visible screen. (x,y>=0)
|
||||
*/
|
||||
protected Rectangle getRectInVirtualSpace(Rectangle r) {
|
||||
return new Rectangle(r.x-fVirtualBounds.x,r.y-fVirtualBounds.y,r.width,r.height);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the extend of the virtual dieplay ares
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
protected void setVirtualExtend(int width, int height) {
|
||||
fVirtualBounds.width=width;
|
||||
fVirtualBounds.height=height;
|
||||
updateScrollbars();
|
||||
updateViewRectangle();
|
||||
}
|
||||
/**
|
||||
* sets the scrolling origin. Also sets the scrollbars.
|
||||
* Does NOT redraw!
|
||||
* Use negative values (move the virtual origin to the top left
|
||||
* to see something in the screen (which is located at (0,0))
|
||||
* @param x
|
||||
* @param y
|
||||
*/
|
||||
protected void setVirtualOrigin(int x, int y) {
|
||||
fVirtualBounds.x=x;
|
||||
fVirtualBounds.y=y;
|
||||
getHorizontalBar().setSelection(-x);
|
||||
getVerticalBar().setSelection(-y);
|
||||
updateViewRectangle();
|
||||
}
|
||||
protected Rectangle getVirtualBounds() {
|
||||
return cloneRectangle(fVirtualBounds);
|
||||
}
|
||||
/**
|
||||
* @param x
|
||||
* @return the virtual coordinate in scree space
|
||||
*/
|
||||
protected int virtualXtoScreen(int x) {
|
||||
return x+fVirtualBounds.x;
|
||||
}
|
||||
protected int virtualYtoScreen(int y) {
|
||||
return y+fVirtualBounds.y;
|
||||
}
|
||||
protected int screenXtoVirtual(int x) {
|
||||
return x-fVirtualBounds.x;
|
||||
}
|
||||
protected int screenYtoVirtual(int y) {
|
||||
return y-fVirtualBounds.y;
|
||||
}
|
||||
/** called when the viewed part is changing */
|
||||
private Rectangle fViewRectangle=new Rectangle(0,0,0,0);
|
||||
void updateViewRectangle() {
|
||||
if(
|
||||
fViewRectangle.x==-fVirtualBounds.x
|
||||
&& fViewRectangle.y==-fVirtualBounds.y
|
||||
&& fViewRectangle.width==fClientArea.width
|
||||
&& fViewRectangle.height==fClientArea.height
|
||||
)
|
||||
return;
|
||||
fViewRectangle.x=-fVirtualBounds.x;
|
||||
fViewRectangle.y=-fVirtualBounds.y;
|
||||
fViewRectangle.width=fClientArea.width;
|
||||
fViewRectangle.height=fClientArea.height;
|
||||
viewRectangleChanged(fViewRectangle.x,fViewRectangle.y,fViewRectangle.width,fViewRectangle.height);
|
||||
}
|
||||
protected Rectangle getViewRectangle() {
|
||||
return cloneRectangle(fViewRectangle);
|
||||
}
|
||||
private Rectangle cloneRectangle(Rectangle r) {
|
||||
return new Rectangle(r.x,r.y,r.width,r.height);
|
||||
}
|
||||
/**
|
||||
* Called when the viewed part has changed.
|
||||
* Override when you need this information....
|
||||
* Is only called if the values change!
|
||||
* @param x visible in virtual space
|
||||
* @param y visible in virtual space
|
||||
* @param width
|
||||
* @param height
|
||||
*/
|
||||
protected void viewRectangleChanged(int x, int y, int width, int height) {
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
private void updateScrollbars() {
|
||||
// don't get into infinite loops....
|
||||
if(!fInUpdateScrollbars) {
|
||||
fInUpdateScrollbars=true;
|
||||
try {
|
||||
doUpdateScrollbar();
|
||||
} finally {
|
||||
fInUpdateScrollbars=false;
|
||||
}
|
||||
}
|
||||
}
|
||||
private void doUpdateScrollbar() {
|
||||
Point size= getSize();
|
||||
Rectangle clientArea= getClientArea();
|
||||
|
||||
ScrollBar horizontal= getHorizontalBar();
|
||||
if (fVirtualBounds.width <= clientArea.width) {
|
||||
// TODO IMPORTANT in ScrollBar.setVisible comment out the line
|
||||
// that checks 'isvisible' and returns (at the beginning)
|
||||
horizontal.setVisible(false);
|
||||
horizontal.setSelection(0);
|
||||
} else {
|
||||
horizontal.setPageIncrement(clientArea.width - horizontal.getIncrement());
|
||||
int max= fVirtualBounds.width + (size.x - clientArea.width);
|
||||
horizontal.setMaximum(max);
|
||||
horizontal.setThumb(size.x > max ? max : size.x);
|
||||
horizontal.setVisible(true);
|
||||
}
|
||||
|
||||
ScrollBar vertical= getVerticalBar();
|
||||
if (fVirtualBounds.height <= clientArea.height) {
|
||||
vertical.setVisible(false);
|
||||
vertical.setSelection(0);
|
||||
} else {
|
||||
vertical.setPageIncrement(clientArea.height - vertical.getIncrement());
|
||||
int max= fVirtualBounds.height + (size.y - clientArea.height);
|
||||
vertical.setMaximum(max);
|
||||
vertical.setThumb(size.y > max ? max : size.y);
|
||||
vertical.setVisible(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
|
||||
/**
|
||||
* A writable matrix of characters and {@link Style}. This is intended to be the
|
||||
* low level representation of the text of a Terminal. Higher layers are responsible
|
||||
* to fill the text and styles into this representation.
|
||||
*
|
||||
* <p><b>Note: </b> Implementations of this interface has to be thread safe.
|
||||
* <p><b>Note: </b> This interface is not intended to be implemented by clients.
|
||||
*/
|
||||
public interface ITerminalTextData extends ITerminalTextDataReadOnly {
|
||||
|
||||
/**
|
||||
* Sets the dimensions of the data. If the dimensions are smaller than the current
|
||||
* dimensions, the lines will be chopped. If the dimensions are bigger, then
|
||||
* the new elements will be filled with 0 chars and null Style.
|
||||
* @param height
|
||||
* @param width
|
||||
*/
|
||||
void setDimensions(int height, int width);
|
||||
|
||||
void setMaxHeight(int height);
|
||||
int getMaxHeight();
|
||||
|
||||
/**
|
||||
* Set a single character and the associated {@link Style}.
|
||||
* @param line line must be >=0 and < height
|
||||
* @param column column must be >=0 and < width
|
||||
* @param c the new character at this position
|
||||
* @param style the style or null
|
||||
*/
|
||||
void setChar(int line, int column, char c, Style style);
|
||||
|
||||
/**
|
||||
* Set an array of characters showing in the same {@link Style}.
|
||||
* @param line line must be >=0 and < height
|
||||
* @param column column must be >=0 and < width
|
||||
* @param chars the new characters at this position
|
||||
* @param style the style or null
|
||||
*/
|
||||
void setChars(int line, int column, char[] chars, Style style);
|
||||
|
||||
/**
|
||||
* Set a subrange of an array of characters showing in the same {@link Style}.
|
||||
* @param line line must be >=0 and < height
|
||||
* @param column column must be >=0 and < width
|
||||
* @param chars the new characters at this position
|
||||
* @param start the start index in the chars array
|
||||
* @param len the number of characters to insert. Characters beyond width are not inserted.
|
||||
* @param style the style or null
|
||||
*/
|
||||
void setChars(int line, int column, char[] chars, int start, int len, Style style);
|
||||
|
||||
|
||||
/**
|
||||
* Cleans the entire line.
|
||||
* @param line
|
||||
*/
|
||||
void cleanLine(int line);
|
||||
// /**
|
||||
// * @param line
|
||||
// * @return true if this line belongs to the previous line but is simply
|
||||
// * wrapped.
|
||||
// */
|
||||
// boolean isWrappedLine(int line);
|
||||
//
|
||||
// /**
|
||||
// * Makes this line an extension to the previous line. Wrapped lines get folded back
|
||||
// * when the width of the terminal changes
|
||||
// * @param line
|
||||
// * @param extendsPreviousLine
|
||||
// */
|
||||
// void setWrappedLine(int line, boolean extendsPreviousLine);
|
||||
|
||||
/**
|
||||
* Shifts some lines up or down. The "empty" space is filled with <code>'\000'</code> chars
|
||||
* and <code>null</code> {@link Style}
|
||||
* <p>To illustrate shift, here is some sample data:
|
||||
* <pre>
|
||||
* 0 aaaa
|
||||
* 1 bbbb
|
||||
* 2 cccc
|
||||
* 3 dddd
|
||||
* 4 eeee
|
||||
* </pre>
|
||||
*
|
||||
* Shift a region of 3 lines <b>up</b> by one line <code>shift(1,3,-1)</code>
|
||||
* <pre>
|
||||
* 0 aaaa
|
||||
* 1 cccc
|
||||
* 2 dddd
|
||||
* 3
|
||||
* 4 eeee
|
||||
* </pre>
|
||||
*
|
||||
*
|
||||
* Shift a region of 3 lines <b>down</b> by one line <code>shift(1,3,1)</code>
|
||||
* <pre>
|
||||
* 0 aaaa
|
||||
* 1
|
||||
* 2 bbbb
|
||||
* 3 cccc
|
||||
* 4 eeee
|
||||
* </pre>
|
||||
* @param startLine the start line of the shift
|
||||
* @param size the number of lines to shift
|
||||
* @param shift how much scrolling is done. New scrolled area is filled with <code>'\000</code>'.
|
||||
* Negative number means scroll down, positive scroll up (see example above).
|
||||
*/
|
||||
void scroll(int startLine, int size, int shift);
|
||||
|
||||
/**Adds a new line to the terminal. If maxHeigth is reached, the entire terminal
|
||||
* will be scrolled. Else a line will be added.
|
||||
*/
|
||||
void addLine();
|
||||
/**
|
||||
* Copies the entire source into this and changes the size accordingly
|
||||
* @param source
|
||||
*/
|
||||
void copy(ITerminalTextData source);
|
||||
/**
|
||||
* Copy a sourceLine from source to this at destLine.
|
||||
* @param source
|
||||
* @param sourceLine
|
||||
* @param destLine
|
||||
*/
|
||||
void copyLine(ITerminalTextData source,int sourceLine, int destLine);
|
||||
/**
|
||||
* Copy <code>length</code> lines from source starting at sourceLine into this starting at
|
||||
* destLine.
|
||||
* @param source
|
||||
* @param sourceStartLine
|
||||
* @param destStartLine
|
||||
* @param length
|
||||
*/
|
||||
void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine,int length);
|
||||
|
||||
void setCursorLine(int line);
|
||||
void setCursorColumn(int column);
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
|
||||
public interface ITerminalTextDataReadOnly {
|
||||
|
||||
/**
|
||||
* @return the width of the terminal
|
||||
*/
|
||||
int getWidth();
|
||||
|
||||
/**
|
||||
* @return the height of the terminal
|
||||
*/
|
||||
int getHeight();
|
||||
|
||||
/**
|
||||
* @param line be >=0 and < height
|
||||
* @param startCol must be >=0 and < width
|
||||
* @param numberOfCols must be > 0
|
||||
* @return a the line segments of the specified range
|
||||
*/
|
||||
LineSegment[] getLineSegments(int line, int startCol, int numberOfCols);
|
||||
|
||||
/**
|
||||
* @param line must be >=0 and < height
|
||||
* @param column must be >=0 and < width
|
||||
* @return the character at column,line
|
||||
*/
|
||||
char getChar(int line, int column);
|
||||
|
||||
/**
|
||||
* @param line must be >=0 and < height
|
||||
* @param column must be >=0 and < width
|
||||
* @return style at column,line or null
|
||||
*/
|
||||
Style getStyle(int line, int column);
|
||||
|
||||
/**
|
||||
* Creates a new instance of {@link ITerminalTextDataSnapshot} that
|
||||
* can be used to track changes. Make sure to call {@link ITerminalTextDataSnapshot#detach()}
|
||||
* if you don't need the snapshots anymore.
|
||||
* <p><b>Note: </b>A new snapshot is empty and needs a call to {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)} to
|
||||
* get its initial values. You might want to setup the snapshot to your needs by calling
|
||||
* {@link ITerminalTextDataSnapshot#setInterestWindow(int, int)}.
|
||||
* </p>
|
||||
* @return a new instance of {@link ITerminalTextDataSnapshot} that "listens" to changes of
|
||||
* <code>this</code>.
|
||||
*/
|
||||
public ITerminalTextDataSnapshot makeSnapshot();
|
||||
|
||||
char[] getChars(int line);
|
||||
Style[] getStyles(int line);
|
||||
|
||||
/**
|
||||
* @return the line in which the cursor is at the moment
|
||||
*/
|
||||
int getCursorLine();
|
||||
/**
|
||||
* @return the column at which the cursor is at the moment
|
||||
*/
|
||||
int getCursorColumn();
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
/**
|
||||
* This class maintains a snapshot of an instance of {@link ITerminalTextData}.
|
||||
* While the {@link ITerminalTextData} continues changing, the snapshot remains
|
||||
* unchanged until the next snapshot is taken by calling {@link #updateSnapshot(boolean)}.
|
||||
* This is important, because the {@link ITerminalTextData} might get
|
||||
* modified by another thread. Suppose you would want to draw the content of
|
||||
* the {@link ITerminalTextData} using the following loop:
|
||||
* <pre>
|
||||
* for(int line=0;line<term.getHeight();line++)
|
||||
* for(int column=0; column<term.getWidth();column++)
|
||||
* drawCharacter(column,line,term.getChar(column,line),term.getStyle(column,line));
|
||||
* </pre>
|
||||
* This might fail because the background thread could change the dimensions of the
|
||||
* {@link ITerminalTextData} while you iterate the loop. One solution would be to
|
||||
* put a <code>synchronized(term){}</code> statement around the code. This has
|
||||
* two problems: 1. you would have to know about the internals of the synchronisation
|
||||
* of {@link ITerminalTextData}. 2. The other thread that changes {@link ITerminalTextData}
|
||||
* is blocked while the potentially slow drawing is done.
|
||||
* <p>
|
||||
* <b>Solution:</b> Take a snapshot of the terminal and use the snapshot to draw
|
||||
* the content. There is no danger that the data structure get changed while
|
||||
* you draw. There are also methods to find out what has changed to minimize
|
||||
* the number of lines that get redrawn.</p>
|
||||
*
|
||||
* <p><b>Drawing optimization</b>: To optimize redrawing of changed lines, this class keeps
|
||||
* track of lines that have changed since the previous snapshot.</p>
|
||||
*
|
||||
* <pre>
|
||||
* // iterate over the potentially changed lines
|
||||
* for(int line=snap.getFirstChangedLine();line<=snap.getLastChangedLine();line++)
|
||||
* // redraw only if the line has changed
|
||||
* if(snap.hasLineChanged(line))
|
||||
* for(int column=0; column<snap.getWidth();column++)
|
||||
* drawCharacter(column,line,snap.getChar(column,line),snap.getStyle(column,line));
|
||||
* </pre>
|
||||
*
|
||||
* <p><b>Scroll optimization:</b> Often new lines are appended at the bottom of the
|
||||
* terminal and the rest of the lines are scrolled up. In this case all lines would be
|
||||
* marked as changed. To optimize for this
|
||||
* case, {@link #updateSnapshot(boolean)} can be called with <code>true</code> for
|
||||
* the <code>detectScrolling</code> parameter. The object will keep track of scrolling.
|
||||
* The UI must <b>first</b> handle the scrolling and then use the {@link #hasLineChanged(int)}
|
||||
* method to determine scrolling:
|
||||
* <pre>
|
||||
* // scroll the visible region of the UI <b>before</b> drawing the changed lines.
|
||||
* doUIScrolling(snap.getScrollChangeY(),snap.getScrollChangeN(),snap.getScrollChangeShift());
|
||||
* // iterate over the potentially changed lines
|
||||
* for(int line=snap.getFirstChangedLine();line<=snap.getFirstChangedLine();line++)
|
||||
* // redraw only if the line has changed
|
||||
* if(snap.hasLineChanged(line))
|
||||
* for(int column=0; column<snap.getWidth();column++)
|
||||
* drawCharacter(column,line,snap.getChar(column,line),snap.getStyle(column,line));
|
||||
* </pre>
|
||||
* </p>
|
||||
*
|
||||
* <p><b>Note</b>: This interface is not intended to be implemented by clients.</p>
|
||||
* <p><b>Threading Note</b>: This class is not thread save! All methods have to be called by
|
||||
* the a same thread, that created the instance by calling
|
||||
* {@link ITerminalTextDataReadOnly#makeSnapshot()}. </p>
|
||||
*/
|
||||
public interface ITerminalTextDataSnapshot extends ITerminalTextDataReadOnly {
|
||||
/**
|
||||
* This listener gets called when the current snapshot
|
||||
* is out of date. Calling {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)}
|
||||
* will have an effect. Once the {@link #snapshotOutOfDate(ITerminalTextDataSnapshot)} method is called,
|
||||
* it will not be called until {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)}
|
||||
* is called and a new snapshot needs to be updated again.
|
||||
* <p>
|
||||
* A typical terminal view would not update the snapshot immediately
|
||||
* after the {@link #snapshotOutOfDate(ITerminalTextDataSnapshot)} has been called. It would introduce a
|
||||
* delay to update the UI (and the snapshot} 10 or 20 times per second.
|
||||
*
|
||||
* <p>Make sure you don't spend too much time in this method.
|
||||
*/
|
||||
interface SnapshotOutOfDateListener {
|
||||
/**
|
||||
* Gets called when the snapshot is out of date. To get the snapshot up to date,
|
||||
* call {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)}.
|
||||
* @param snapshot The snapshot that is out of date
|
||||
*/
|
||||
void snapshotOutOfDate(ITerminalTextDataSnapshot snapshot);
|
||||
}
|
||||
void addListener(SnapshotOutOfDateListener listener);
|
||||
void removeListener(SnapshotOutOfDateListener listener);
|
||||
|
||||
/**
|
||||
* Ends the listening to the {@link ITerminalTextData}. After this
|
||||
* has been called no new snapshot data is collected.
|
||||
*/
|
||||
void detach();
|
||||
/**
|
||||
* @return true if the data has changed since the previous snapshot.
|
||||
*/
|
||||
boolean isOutOfDate();
|
||||
|
||||
/**
|
||||
* The window of interest is the region the snapshot should track.
|
||||
* Changes outside this region are ignored. The change takes effect after
|
||||
* an update!
|
||||
* @param startLine -1 means track the end of the data
|
||||
* @param size number of lines to track. A size of -1 means track all.
|
||||
*/
|
||||
void setInterestWindow(int startLine, int size);
|
||||
int getInterestWindowStartLine();
|
||||
int getInterestWindowSize();
|
||||
|
||||
/**
|
||||
* Create a new snapshot of the {@link ITerminalTextData}. It will efficiently
|
||||
* copy the data of the {@link ITerminalTextData} into an internal representation.
|
||||
* The snapshot also keeps track of the changes since the previous snapshot.
|
||||
* <p>With the methods {@link #getFirstChangedLine()}, {@link #getLastChangedLine()} and
|
||||
* {@link #hasLineChanged(int)}
|
||||
* you can find out what has changed in the current snapshot since the previous snapshot.
|
||||
* @param detectScrolling if <code>true</code> the snapshot tries to identify scroll
|
||||
* changes since the last snapshot. In this case the information about scrolling
|
||||
* can be retrieved using the following methods:
|
||||
* {@link #getScrollWindowStartLine()}, {@link #getScrollWindowSize()} and {@link #getScrollWindowShift()}
|
||||
* <br><b>Note:</b> The method {@link #hasLineChanged(int)} returns changes <b>after</b> the
|
||||
* scrolling has been applied.
|
||||
*/
|
||||
void updateSnapshot(boolean detectScrolling);
|
||||
|
||||
/**
|
||||
* @return The first line changed in this snapshot compared
|
||||
* to the previous snapshot.
|
||||
*
|
||||
* <p><b>Note:</b> If no line has changed, this
|
||||
* returns {@link Integer#MAX_VALUE}
|
||||
*
|
||||
* <p><b>Note:</b> if {@link #updateSnapshot(boolean)} has been called with <code>true</code>,
|
||||
* then this does not include lines that only have been scrolled. This is the
|
||||
* first line that has changed <b>after</b> the scroll has been applied.
|
||||
*/
|
||||
int getFirstChangedLine();
|
||||
|
||||
/**
|
||||
* @return The last line changed in this snapshot compared
|
||||
* to the previous snapshot. If the height has changed since the
|
||||
* last update of the snapshot, then the returned value is within
|
||||
* the new dimensions.
|
||||
*
|
||||
* <p><b>Note:</b> If no line has changed, this returns <code>-1</code>
|
||||
*
|
||||
* <p><b>Note:</b> if {@link #updateSnapshot(boolean)} has been called with <code>true</code>,
|
||||
* then this does not include lines that only have been scrolled. This is the
|
||||
* last line that has changed <b>after</b> the scroll has been applied.
|
||||
*
|
||||
* <p>A typical for loop using this method would look like this (note the <code><=</code> in the for loop):
|
||||
* <pre>
|
||||
* for(int line=snap.{@link #getFirstChangedLine()}; line <b><=</b> snap.getLastChangedLine(); line++)
|
||||
* if(snap.{@link #hasLineChanged(int) hasLineChanged(line)})
|
||||
* doSomething(line);
|
||||
* </pre>
|
||||
*/
|
||||
int getLastChangedLine();
|
||||
|
||||
/**
|
||||
* @param line
|
||||
* @return true if the line has changed since the previous snapshot
|
||||
*/
|
||||
boolean hasLineChanged(int line);
|
||||
|
||||
boolean hasDimensionsChanged();
|
||||
|
||||
/**
|
||||
* @return true if the terminal has changed (and not just the
|
||||
* window of interest)
|
||||
*/
|
||||
boolean hasTerminalChanged();
|
||||
/**
|
||||
* If {@link #updateSnapshot(boolean)} was called with <code>true</code>, then this method
|
||||
* returns the top of the scroll region.
|
||||
* @return The first line scrolled in this snapshot compared
|
||||
* to the previous snapshot. See also {@link ITerminalTextData#scroll(int, int, int)}.
|
||||
*/
|
||||
int getScrollWindowStartLine();
|
||||
|
||||
/**
|
||||
* If {@link #updateSnapshot(boolean)} was called with <code>true</code>, then this method
|
||||
* returns the size of the scroll region.
|
||||
* @return The number of lines scrolled in this snapshot compared
|
||||
* to the previous snapshot. See also {@link ITerminalTextData#scroll(int, int, int)}
|
||||
* If nothing has changed, 0 is returned.
|
||||
*/
|
||||
int getScrollWindowSize();
|
||||
|
||||
/**
|
||||
* If {@link #updateSnapshot(boolean)} was called with <code>true</code>, then this method
|
||||
* returns number of lines moved by the scroll region.
|
||||
* @return The the scroll shift of this snapshot compared
|
||||
* to the previous snapshot. See also {@link ITerminalTextData#scroll(int, int, int)}
|
||||
*/
|
||||
int getScrollWindowShift();
|
||||
|
||||
/**
|
||||
* @return The {@link ITerminalTextData} on that this instance is observing.
|
||||
*/
|
||||
ITerminalTextData getTerminalTextData();
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
|
||||
public class LineSegment {
|
||||
private final String fText;
|
||||
private final int fCol;
|
||||
private final Style fStyle;
|
||||
public LineSegment(int col, String text, Style style) {
|
||||
fCol = col;
|
||||
fText = text;
|
||||
fStyle = style;
|
||||
}
|
||||
public Style getStyle() {
|
||||
return fStyle;
|
||||
}
|
||||
public String getText() {
|
||||
return fText;
|
||||
}
|
||||
public int getColumn() {
|
||||
return fCol;
|
||||
}
|
||||
public String toString() {
|
||||
return "LineSegment("+fCol+", \""+fText+"\","+fStyle+")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author scharf
|
||||
* Flyweight
|
||||
* Threadsafe.
|
||||
*
|
||||
*/
|
||||
// TODO add an Object for user data, use weak map to keep track of styles with associated
|
||||
// user data
|
||||
public class Style {
|
||||
private final StyleColor fForground;
|
||||
private final StyleColor fBackground;
|
||||
private final boolean fBold;
|
||||
private final boolean fBlink;
|
||||
private final boolean fUnderline;
|
||||
private final boolean fReverse;
|
||||
private final static Map fgStyles=new HashMap();
|
||||
private Style(StyleColor forground, StyleColor background, boolean bold, boolean blink, boolean underline, boolean reverse) {
|
||||
fForground = forground;
|
||||
fBackground = background;
|
||||
fBold = bold;
|
||||
fBlink = blink;
|
||||
fUnderline = underline;
|
||||
fReverse = reverse;
|
||||
}
|
||||
public static Style getStyle(StyleColor forground, StyleColor background, boolean bold, boolean blink, boolean underline, boolean reverse) {
|
||||
Style style = new Style(forground,background, bold, blink,underline,reverse);
|
||||
Style cached;
|
||||
synchronized (fgStyles) {
|
||||
cached=(Style) fgStyles.get(style);
|
||||
if(cached==null) {
|
||||
cached=style;
|
||||
fgStyles.put(cached, cached);
|
||||
}
|
||||
}
|
||||
return cached;
|
||||
}
|
||||
public static Style getStyle(String forground, String background) {
|
||||
return getStyle(StyleColor.getStyleColor(forground), StyleColor.getStyleColor(background),false,false,false,false);
|
||||
}
|
||||
public static Style getStyle(StyleColor forground, StyleColor background) {
|
||||
return getStyle(forground, background,false,false,false,false);
|
||||
}
|
||||
public Style setForground(StyleColor forground) {
|
||||
return getStyle(forground,fBackground,fBold,fBlink,fUnderline,fReverse);
|
||||
}
|
||||
public Style setBackground(StyleColor background) {
|
||||
return getStyle(fForground,background,fBold,fBlink,fUnderline,fReverse);
|
||||
}
|
||||
public Style setForground(String colorName) {
|
||||
return getStyle(StyleColor.getStyleColor(colorName),fBackground,fBold,fBlink,fUnderline,fReverse);
|
||||
}
|
||||
public Style setBackground(String colorName) {
|
||||
return getStyle(fForground,StyleColor.getStyleColor(colorName),fBold,fBlink,fUnderline,fReverse);
|
||||
}
|
||||
public Style setBold(boolean bold) {
|
||||
return getStyle(fForground,fBackground,bold,fBlink,fUnderline,fReverse);
|
||||
}
|
||||
public Style setBlink(boolean blink) {
|
||||
return getStyle(fForground,fBackground,fBold,blink,fUnderline,fReverse);
|
||||
}
|
||||
public Style setUnderline(boolean underline) {
|
||||
return getStyle(fForground,fBackground,fBold,fBlink,underline,fReverse);
|
||||
}
|
||||
public Style setReverse(boolean reverse) {
|
||||
return getStyle(fForground,fBackground,fBold,fBlink,fUnderline,reverse);
|
||||
}
|
||||
public StyleColor getBackground() {
|
||||
return fBackground;
|
||||
}
|
||||
public boolean isBlink() {
|
||||
return fBlink;
|
||||
}
|
||||
public boolean isBold() {
|
||||
return fBold;
|
||||
}
|
||||
public StyleColor getForground() {
|
||||
return fForground;
|
||||
}
|
||||
public boolean isReverse() {
|
||||
return fReverse;
|
||||
}
|
||||
public boolean isUnderline() {
|
||||
return fUnderline;
|
||||
}
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + ((fBackground == null) ? 0 : fBackground.hashCode());
|
||||
result = prime * result + (fBlink ? 1231 : 1237);
|
||||
result = prime * result + (fBold ? 1231 : 1237);
|
||||
result = prime * result + ((fForground == null) ? 0 : fForground.hashCode());
|
||||
result = prime * result + (fReverse ? 1231 : 1237);
|
||||
result = prime * result + (fUnderline ? 1231 : 1237);
|
||||
return result;
|
||||
}
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj)
|
||||
return true;
|
||||
if (obj == null)
|
||||
return false;
|
||||
if (getClass() != obj.getClass())
|
||||
return false;
|
||||
final Style other = (Style) obj;
|
||||
// background == is the same as equals
|
||||
if (fBackground != other.fBackground)
|
||||
return false;
|
||||
if (fBlink != other.fBlink)
|
||||
return false;
|
||||
if (fBold != other.fBold)
|
||||
return false;
|
||||
if (fForground != other.fForground)
|
||||
return false;
|
||||
if (fReverse != other.fReverse)
|
||||
return false;
|
||||
if (fUnderline != other.fUnderline)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
public String toString() {
|
||||
StringBuffer result=new StringBuffer();
|
||||
result.append("Style(foreground="); //$NON-NLS-1$
|
||||
result.append(fForground);
|
||||
result.append(", background="); //$NON-NLS-1$
|
||||
result.append(fBackground);
|
||||
if(fBlink)
|
||||
result.append(", blink"); //$NON-NLS-1$
|
||||
if(fBold)
|
||||
result.append(", bold"); //$NON-NLS-1$
|
||||
if(fBlink)
|
||||
result.append(", blink"); //$NON-NLS-1$
|
||||
if(fReverse)
|
||||
result.append(", reverse"); //$NON-NLS-1$
|
||||
if(fUnderline)
|
||||
result.append(", underline"); //$NON-NLS-1$
|
||||
result.append(")"); //$NON-NLS-1$
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
*
|
||||
* Flyweight
|
||||
* Threadsafe.
|
||||
*/
|
||||
public class StyleColor {
|
||||
private final static Map fgStyleColors=new HashMap();
|
||||
final String fName;
|
||||
|
||||
/**
|
||||
* @param name the name of the color. It is up to the UI to associate a
|
||||
* named color with a visual representation
|
||||
* @return a StyleColor
|
||||
*/
|
||||
public static StyleColor getStyleColor(String name) {
|
||||
StyleColor result;
|
||||
synchronized (fgStyleColors) {
|
||||
result=(StyleColor) fgStyleColors.get(name);
|
||||
if(result==null) {
|
||||
result=new StyleColor(name);
|
||||
fgStyleColors.put(name, result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
// nobody except the factory method is allowed to instantiate this class!
|
||||
private StyleColor(String name) {
|
||||
fName = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return fName;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return fName;
|
||||
}
|
||||
// no need to override equals and hashCode, because Object uses object identity
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*******************************************************************************
|
||||
* Copyright (c) 2007 Wind River Systems, Inc. and others.
|
||||
* All rights reserved. This program and the accompanying materials
|
||||
* are made available under the terms of the Eclipse Public License v1.0
|
||||
* which accompanies this distribution, and is available at
|
||||
* http://www.eclipse.org/legal/epl-v10.html
|
||||
*
|
||||
* Contributors:
|
||||
* Michael Scharf (Wind River) - initial API and implementation
|
||||
*******************************************************************************/
|
||||
package org.eclipse.tm.terminal.model;
|
||||
|
||||
import org.eclipse.tm.internal.terminal.model.SynchronizedTerminalTextData;
|
||||
import org.eclipse.tm.internal.terminal.model.TerminalTextData;
|
||||
|
||||
public class TerminalTextDataFactory {
|
||||
static public ITerminalTextData makeTerminalTextData() {
|
||||
return new SynchronizedTerminalTextData(new TerminalTextData());
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue