From 9eb580a8f2da1ccfaba7e57f2b880f752fd37ea3 Mon Sep 17 00:00:00 2001 From: Michael Scharf Date: Fri, 1 Dec 2006 03:08:19 +0000 Subject: [PATCH] bug 165177: split the plugin into the terminal view and connection contributions --- org.eclipse.tm.terminal-feature/.project | 17 + .../build.properties | 1 + org.eclipse.tm.terminal-feature/feature.xml | 32 + .../.project | 17 + .../build.properties | 1 + .../feature.xml | 32 + org.eclipse.tm.terminal.serial/.classpath | 8 + org.eclipse.tm.terminal.serial/.project | 34 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 14 + org.eclipse.tm.terminal.serial/README.txt | 4 + .../build.properties | 16 + .../plugin.properties | 6 + org.eclipse.tm.terminal.serial/plugin.xml | 9 + .../internal/serial/ISerialSettings.java | 28 + .../internal/serial/SerialConnectWorker.java | 64 + .../internal/serial/SerialConnector.java | 197 ++ .../internal/serial/SerialMessages.java | 30 + .../internal/serial/SerialMessages.properties | 21 + .../internal/serial/SerialPortHandler.java | 107 + .../internal/serial/SerialProperties.java | 159 ++ .../internal/serial/SerialSettings.java | 196 ++ .../internal/serial/SerialSettingsPage.java | 137 ++ org.eclipse.tm.terminal.view-feature/.project | 17 + .../build.properties | 1 + .../feature.xml | 33 + org.eclipse.tm.terminal.view/.classpath | 7 + org.eclipse.tm.terminal.view/.project | 34 + .../.settings/org.eclipse.jdt.core.prefs | 7 + .../.settings/org.eclipse.jdt.ui.prefs | 3 + .../META-INF/MANIFEST.MF | 13 + org.eclipse.tm.terminal.view/build.properties | 17 + .../icons/clcl16/connect_co.gif | Bin .../icons/clcl16/disconnect_co.gif | Bin .../icons/clcl16/newterminal.gif | Bin .../icons/clcl16/properties_tsk.gif | Bin .../icons/cview16/terminal_view.gif | Bin .../icons/dlcl16/connect_co.gif | Bin .../icons/dlcl16/disconnect_co.gif | Bin .../icons/dlcl16/newterminal.gif | Bin .../icons/dlcl16/properties_tsk.gif | Bin .../icons/elcl16/connect_co.gif | Bin .../icons/elcl16/disconnect_co.gif | Bin .../icons/elcl16/newterminal.gif | Bin .../icons/elcl16/properties_tsk.gif | Bin .../icons/eview16/terminal_view.gif | Bin .../plugin.properties | 17 + org.eclipse.tm.terminal.view/plugin.xml | 128 + .../internal/actions/ActionMessages.java | 31 + .../actions/ActionMessages.properties | 21 + .../internal/actions/TerminalAction.java | 67 + .../actions}/TerminalActionClearAll.java | 15 +- .../actions}/TerminalActionConnect.java | 21 +- .../internal/actions}/TerminalActionCopy.java | 13 +- .../internal/actions}/TerminalActionCut.java | 13 +- .../actions}/TerminalActionDisconnect.java | 21 +- .../actions}/TerminalActionNewTerminal.java | 22 +- .../actions}/TerminalActionPaste.java | 13 +- .../actions}/TerminalActionSelectAll.java | 14 +- .../actions}/TerminalActionSettings.java | 21 +- .../terminal/internal/view/ITerminalView.java | 31 + .../terminal/internal/view/ImageConsts.java | 40 + .../tm/terminal/internal/view/PageBook.java | 113 + .../view/SettingStorePrefixDecorator.java | 35 + .../terminal/internal/view/SettingsStore.java | 46 + .../internal/view/TerminalPreferencePage.java | 150 ++ .../internal/view/TerminalSettingsDlg.java | 143 ++ .../terminal/internal/view/TerminalView.java | 657 +++++ .../internal/view/TerminalViewPlugin.java | 140 ++ .../terminal/internal/view/ViewMessages.java | 35 + .../internal/view/ViewMessages.properties | 27 + .../eclipse/tm/terminal/view/Activator.java | 61 + org.eclipse.tm.terminal/.classpath | 2 +- org.eclipse.tm.terminal/.project | 6 + .../.settings/org.eclipse.jdt.core.prefs | 52 +- org.eclipse.tm.terminal/META-INF/MANIFEST.MF | 12 +- org.eclipse.tm.terminal/README.txt | 0 org.eclipse.tm.terminal/build.properties | 14 + org.eclipse.tm.terminal/plugin.properties | 11 - org.eclipse.tm.terminal/plugin.xml | 127 +- .../schema/terminalConnector.exsd | 105 + .../eclipse/tm/terminal/ISettingsPage.java | 47 + .../eclipse/tm/terminal/ISettingsStore.java | 40 + .../tm/terminal/ITerminalConnector.java | 98 + .../eclipse/tm/terminal/ITerminalControl.java | 65 + .../src/org/eclipse/tm/terminal/Logger.java | 154 +- .../src/org/eclipse/tm/terminal/Messages.java | 40 - .../eclipse/tm/terminal/Messages.properties | 43 - .../eclipse/tm/terminal/TelnetConnection.java | 796 ------ .../org/eclipse/tm/terminal/TelnetOption.java | 756 ------ .../eclipse/tm/terminal/TerminalAction.java | 119 - .../terminal/TerminalConnectorExtension.java | 48 + .../eclipse/tm/terminal/TerminalConsts.java | 114 - .../org/eclipse/tm/terminal/TerminalCtrl.java | 1573 ------------ .../org/eclipse/tm/terminal/TerminalMsg.java | 44 - .../tm/terminal/TerminalNetworkPortMap.java | 104 - .../eclipse/tm/terminal/TerminalPlugin.java | 294 --- .../tm/terminal/TerminalPreferencePage.java | 265 -- .../tm/terminal/TerminalProperties.java | 278 --- .../eclipse/tm/terminal/TerminalSettings.java | 425 ---- .../tm/terminal/TerminalSettingsDlg.java | 911 ------- .../eclipse/tm/terminal/TerminalState.java | 45 + .../org/eclipse/tm/terminal/TerminalText.java | 2145 ----------------- .../org/eclipse/tm/terminal/TerminalView.java | 1047 -------- .../terminal/control/ITerminalListener.java | 33 + .../control/ITerminalViewControl.java | 46 + .../control/TerminalViewControlFactory.java | 22 + .../control/ITerminalControlForText.java | 36 + .../internal/control/TerminalControl.java | 807 +++++++ .../control/TerminalMessages.java} | 15 +- .../control/TerminalMessages.properties | 14 + .../internal/control/TerminalPlugin.java | 54 + .../internal/control/TerminalText.java | 2081 ++++++++++++++++ .../internal/telnet/ITelnetSettings.java | 12 + .../internal/telnet/NetworkPortMap.java | 53 + .../{ => internal/telnet}/TelnetCodes.java | 2 +- .../internal/telnet/TelnetConnectWorker.java | 69 + .../internal/telnet/TelnetConnection.java | 684 ++++++ .../internal/telnet/TelnetConnector.java | 144 ++ .../internal/telnet/TelnetMessages.java | 27 + .../internal/telnet/TelnetMessages.properties | 16 + .../internal/telnet/TelnetOption.java | 698 ++++++ .../internal/telnet/TelnetProperties.java | 41 + .../internal/telnet/TelnetSettings.java | 89 + .../internal/telnet/TelnetSettingsPage.java | 132 + 125 files changed, 8780 insertions(+), 9239 deletions(-) create mode 100644 org.eclipse.tm.terminal-feature/.project create mode 100644 org.eclipse.tm.terminal-feature/build.properties create mode 100644 org.eclipse.tm.terminal-feature/feature.xml create mode 100644 org.eclipse.tm.terminal.serial-feature/.project create mode 100644 org.eclipse.tm.terminal.serial-feature/build.properties create mode 100644 org.eclipse.tm.terminal.serial-feature/feature.xml create mode 100644 org.eclipse.tm.terminal.serial/.classpath create mode 100644 org.eclipse.tm.terminal.serial/.project create mode 100644 org.eclipse.tm.terminal.serial/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.eclipse.tm.terminal.serial/META-INF/MANIFEST.MF create mode 100644 org.eclipse.tm.terminal.serial/README.txt create mode 100644 org.eclipse.tm.terminal.serial/build.properties create mode 100644 org.eclipse.tm.terminal.serial/plugin.properties create mode 100644 org.eclipse.tm.terminal.serial/plugin.xml create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/ISerialSettings.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnectWorker.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnector.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.properties create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialPortHandler.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialProperties.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettings.java create mode 100644 org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettingsPage.java create mode 100644 org.eclipse.tm.terminal.view-feature/.project create mode 100644 org.eclipse.tm.terminal.view-feature/build.properties create mode 100644 org.eclipse.tm.terminal.view-feature/feature.xml create mode 100644 org.eclipse.tm.terminal.view/.classpath create mode 100644 org.eclipse.tm.terminal.view/.project create mode 100644 org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.core.prefs create mode 100644 org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.ui.prefs create mode 100644 org.eclipse.tm.terminal.view/META-INF/MANIFEST.MF create mode 100644 org.eclipse.tm.terminal.view/build.properties rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/clcl16/connect_co.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/clcl16/disconnect_co.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/clcl16/newterminal.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/clcl16/properties_tsk.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/cview16/terminal_view.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/dlcl16/connect_co.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/dlcl16/disconnect_co.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/dlcl16/newterminal.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/dlcl16/properties_tsk.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/elcl16/connect_co.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/elcl16/disconnect_co.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/elcl16/newterminal.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/elcl16/properties_tsk.gif (100%) rename {org.eclipse.tm.terminal => org.eclipse.tm.terminal.view}/icons/eview16/terminal_view.gif (100%) create mode 100644 org.eclipse.tm.terminal.view/plugin.properties create mode 100644 org.eclipse.tm.terminal.view/plugin.xml create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.properties create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalAction.java rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionClearAll.java (72%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionConnect.java (58%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionCopy.java (79%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionCut.java (80%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionDisconnect.java (58%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionNewTerminal.java (56%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionPaste.java (79%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionSelectAll.java (72%) rename {org.eclipse.tm.terminal/src/org/eclipse/tm/terminal => org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions}/TerminalActionSettings.java (57%) create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ITerminalView.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ImageConsts.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/PageBook.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingStorePrefixDecorator.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingsStore.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalPreferencePage.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalSettingsDlg.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalView.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalViewPlugin.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.java create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.properties create mode 100644 org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/view/Activator.java create mode 100644 org.eclipse.tm.terminal/README.txt create mode 100644 org.eclipse.tm.terminal/build.properties create mode 100644 org.eclipse.tm.terminal/schema/terminalConnector.exsd create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsPage.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsStore.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalConnector.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.properties delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetConnection.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetOption.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalAction.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConnectorExtension.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConsts.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalCtrl.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalMsg.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalNetworkPortMap.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPlugin.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPreferencePage.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalProperties.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettings.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettingsDlg.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalState.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalText.java delete mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalView.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalListener.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalViewControl.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/TerminalViewControlFactory.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/ITerminalControlForText.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalControl.java rename org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/{TerminalTarget.java => internal/control/TerminalMessages.java} (62%) create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.properties create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalPlugin.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalText.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/ITelnetSettings.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/NetworkPortMap.java rename org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/{ => internal/telnet}/TelnetCodes.java (98%) create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnectWorker.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnection.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnector.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.properties create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetOption.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetProperties.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettings.java create mode 100644 org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettingsPage.java diff --git a/org.eclipse.tm.terminal-feature/.project b/org.eclipse.tm.terminal-feature/.project new file mode 100644 index 00000000000..c93208eb484 --- /dev/null +++ b/org.eclipse.tm.terminal-feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal-feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/org.eclipse.tm.terminal-feature/build.properties b/org.eclipse.tm.terminal-feature/build.properties new file mode 100644 index 00000000000..64f93a9f0b7 --- /dev/null +++ b/org.eclipse.tm.terminal-feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.eclipse.tm.terminal-feature/feature.xml b/org.eclipse.tm.terminal-feature/feature.xml new file mode 100644 index 00000000000..fc71c20598a --- /dev/null +++ b/org.eclipse.tm.terminal-feature/feature.xml @@ -0,0 +1,32 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + diff --git a/org.eclipse.tm.terminal.serial-feature/.project b/org.eclipse.tm.terminal.serial-feature/.project new file mode 100644 index 00000000000..44409931fb6 --- /dev/null +++ b/org.eclipse.tm.terminal.serial-feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.serial-feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/org.eclipse.tm.terminal.serial-feature/build.properties b/org.eclipse.tm.terminal.serial-feature/build.properties new file mode 100644 index 00000000000..64f93a9f0b7 --- /dev/null +++ b/org.eclipse.tm.terminal.serial-feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.eclipse.tm.terminal.serial-feature/feature.xml b/org.eclipse.tm.terminal.serial-feature/feature.xml new file mode 100644 index 00000000000..a64b5e45479 --- /dev/null +++ b/org.eclipse.tm.terminal.serial-feature/feature.xml @@ -0,0 +1,32 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + diff --git a/org.eclipse.tm.terminal.serial/.classpath b/org.eclipse.tm.terminal.serial/.classpath new file mode 100644 index 00000000000..3183e6f648e --- /dev/null +++ b/org.eclipse.tm.terminal.serial/.classpath @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/org.eclipse.tm.terminal.serial/.project b/org.eclipse.tm.terminal.serial/.project new file mode 100644 index 00000000000..e16739b9d97 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/.project @@ -0,0 +1,34 @@ + + + org.eclipse.tm.terminal.serial + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + net.sourceforge.metrics.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + net.sourceforge.metrics.nature + + diff --git a/org.eclipse.tm.terminal.serial/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tm.terminal.serial/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..64e6553c55e --- /dev/null +++ b/org.eclipse.tm.terminal.serial/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +#Wed Nov 29 05:39:06 CET 2006 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.source=1.3 diff --git a/org.eclipse.tm.terminal.serial/META-INF/MANIFEST.MF b/org.eclipse.tm.terminal.serial/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..d12a2a04efe --- /dev/null +++ b/org.eclipse.tm.terminal.serial/META-INF/MANIFEST.MF @@ -0,0 +1,14 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.serial;singleton:=true +Bundle-Version: 0.9.0 +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.tm.terminal +Eclipse-LazyStart: false +Bundle-Vendor: %providerName +Bundle-RequiredExecutionEnvironment: J2SE-1.4 +Bundle-ClassPath: ., + comm.jar diff --git a/org.eclipse.tm.terminal.serial/README.txt b/org.eclipse.tm.terminal.serial/README.txt new file mode 100644 index 00000000000..50b8553076d --- /dev/null +++ b/org.eclipse.tm.terminal.serial/README.txt @@ -0,0 +1,4 @@ +Important note: + +In order to compile this plugin, comm has to be installed into +the java installation... \ No newline at end of file diff --git a/org.eclipse.tm.terminal.serial/build.properties b/org.eclipse.tm.terminal.serial/build.properties new file mode 100644 index 00000000000..8e2b821203b --- /dev/null +++ b/org.eclipse.tm.terminal.serial/build.properties @@ -0,0 +1,16 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + comm.jar +src.includes = .classpath,\ + .project,\ + .settings/,\ + META-INF/,\ + README.txt,\ + build.properties,\ + plugin.properties,\ + plugin.xml,\ + src/,\ + comm.jar diff --git a/org.eclipse.tm.terminal.serial/plugin.properties b/org.eclipse.tm.terminal.serial/plugin.properties new file mode 100644 index 00000000000..4caacf9e857 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/plugin.properties @@ -0,0 +1,6 @@ +########################################################################## +# Copyright 2004 Wind River Systems, Inc. All rights reserved. +########################################################################## + +pluginName = Serial Terminal +providerName = Eclipse.org diff --git a/org.eclipse.tm.terminal.serial/plugin.xml b/org.eclipse.tm.terminal.serial/plugin.xml new file mode 100644 index 00000000000..29127ce2604 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/plugin.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/ISerialSettings.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/ISerialSettings.java new file mode 100644 index 00000000000..cfb2ec28682 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/ISerialSettings.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.serial; + +import org.eclipse.tm.terminal.ISettingsStore; + +public interface ISerialSettings { + + String getSerialPort(); + int getBaudRate(); + int getDataBits(); + int getStopBits(); + int getParity(); + int getFlowControl(); + int getTimeout(); + String getStatusString(String strConnected); + void load(ISettingsStore store); + void save(ISettingsStore store); +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnectWorker.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnectWorker.java new file mode 100644 index 00000000000..d561fd396a2 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnectWorker.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.serial; + +import javax.comm.CommPortIdentifier; +import javax.comm.PortInUseException; +import javax.comm.SerialPort; + +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.TerminalState; + +public class SerialConnectWorker extends Thread { + private final ITerminalControl fControl; + private final SerialConnector fConn; + + /** + * UNDER CONSTRUCTION + * @param conn TODO + * @param control TODO + */ + public SerialConnectWorker(SerialConnector conn, ITerminalControl control) { + super(); + fControl = control; + fConn = conn; + fControl.setState(TerminalState.CONNECTING); + } + public void run() { + + try { + fControl.setState(TerminalState.OPENED); + String strID = getClass().getPackage().getName(); + ISerialSettings s=fConn.getSerialSettings(); + + fConn.setSerialPortHandler(new SerialPortHandler(fConn,fControl)); + fConn.setSerialPortIdentifier(CommPortIdentifier.getPortIdentifier(s.getSerialPort())); + int timeoutInMs = s.getTimeout() * 1000; + + SerialPort serialPort=(SerialPort) fConn.getSerialPortIdentifier().open(strID,timeoutInMs); + serialPort.setSerialPortParams(s.getBaudRate(), s.getDataBits(), s.getStopBits(), s.getParity()); + serialPort.setFlowControlMode(s.getFlowControl()); + serialPort.addEventListener(fConn.getSerialPortHandler()); + serialPort.notifyOnDataAvailable(true); + fConn.getSerialPortIdentifier().addPortOwnershipListener(fConn.getSerialPortHandler()); + fConn.setSerialPort(serialPort); + fControl.setState(TerminalState.CONNECTED); + } catch (PortInUseException portInUseException) { + fConn.setPortInUse(true); + fControl.setState(TerminalState.CLOSED); + fControl.setMsg("Connection Error!\n" + portInUseException.getMessage()); //$NON-NLS-1$ + + } catch (Exception exception) { + fControl.setState(TerminalState.CLOSED); + } + } +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnector.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnector.java new file mode 100644 index 00000000000..028ae2f17af --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialConnector.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.serial; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +import javax.comm.CommPortIdentifier; +import javax.comm.SerialPort; + +import org.eclipse.tm.terminal.ISettingsPage; +import org.eclipse.tm.terminal.ISettingsStore; +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; + +public class SerialConnector implements ITerminalConnector { + private OutputStream fOutputStream; + private InputStream fInputStream; + private ITerminalControl fControl; + private SerialPort fSerialPort; + private CommPortIdentifier fSerialPortIdentifier; + private SerialPortHandler fTerminalSerialPortHandler; + private boolean fIsPortInUse; + private final SerialSettings fSettings; + public SerialConnector() { + SerialSettings settins=null; + try { + settins=new SerialSettings(); + } catch (NoClassDefFoundError e) { + // the comm library is not installed + e.printStackTrace(); + } + fSettings=settins; + } + public String getId() { + return getClass().getName(); + } + public boolean isInstalled() { + // check if serial is installed + try { + return SerialPort.class!=null; + } catch (Throwable e) { + return false; + } + } + public SerialConnector(SerialSettings settings) { + fSettings=settings; + } + public void connect(ITerminalControl control) { + Logger.log("entered."); //$NON-NLS-1$ + fControl=control; + SerialConnectWorker worker = new SerialConnectWorker(this, control); + worker.start(); + } + public void disconnect() { + Logger.log("entered."); //$NON-NLS-1$ + + // Fix for SPR 112422. When output is being received from the serial port, the + // below call to removePortOwnershipListener() attempts to lock the serial port + // object, but that object is already locked by another Terminal view thread + // waiting for the SWT display thread to process a syncExec() call. Since this + // method is called on the display thread, the display thread is waiting to + // lock the serial port object and the thread holding the serial port object + // lock is waiting for the display thread to process a syncExec() call, so the + // two threads end up deadlocked, which hangs the Workbench GUI. + // + // The solution is to spawn a short-lived worker thread that calls + // removePortOwnershipListener(), thus preventing the display thread from + // deadlocking with the other Terminal view thread. + + new Thread("Terminal View Serial Port Disconnect Worker") //$NON-NLS-1$ + { + public void run() { + + if (getSerialPortIdentifier() != null) { + getSerialPortIdentifier() + .removePortOwnershipListener(getSerialPortHandler()); + } + + if (getSerialPort() != null) { + getSerialPort().removeEventListener(); + Logger.log("Calling close() on serial port ..."); //$NON-NLS-1$ + getSerialPort().close(); + } + + if (getInputStream() != null) { + try { + getInputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + if (getOutputStream() != null) { + try { + getOutputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + setSerialPortIdentifier(null); + cleanSerialPort(); + setSerialPortHandler(null); + } + + }.start(); + fControl.setState(TerminalState.CLOSED); + } + public InputStream getInputStream() { + return fInputStream; + } + public OutputStream getOutputStream() { + return fOutputStream; + } + private void setInputStream(InputStream inputStream) { + fInputStream = inputStream; + } + private void setOutputStream(OutputStream outputStream) { + fOutputStream = outputStream; + } + public boolean isLocalEcho() { + return false; + } + public void setTerminalSize(int newWidth, int newHeight) { + // TODO + } + + protected SerialPort getSerialPort() { + return fSerialPort; + } + + /** + * sets the socket to null + */ + void cleanSerialPort() { + fSerialPort=null; + setInputStream(null); + setOutputStream(null); + } + + protected void setSerialPort(SerialPort serialPort) throws IOException { + cleanSerialPort(); + if(serialPort!=null) { + fSerialPort = serialPort; + setOutputStream(serialPort.getOutputStream()); + setInputStream(serialPort.getInputStream()); + } + } + protected CommPortIdentifier getSerialPortIdentifier() { + return fSerialPortIdentifier; + } + protected void setSerialPortIdentifier(CommPortIdentifier serialPortIdentifier) { + fSerialPortIdentifier = serialPortIdentifier; + } + void setSerialPortHandler(SerialPortHandler serialPortHandler) { + fTerminalSerialPortHandler=serialPortHandler; + } + SerialPortHandler getSerialPortHandler() { + return fTerminalSerialPortHandler; + } + public boolean isPortInUse() { + return fIsPortInUse; + } + public void setPortInUse(boolean b) { + fIsPortInUse=true; + + } + public ISerialSettings getSerialSettings() { + return fSettings; + } + public ISettingsPage makeSettingsPage() { + return new SerialSettingsPage(fSettings); + } + public String getStatusString(String strConnected) { + return fSettings.getStatusString(strConnected); + } + public void load(ISettingsStore store) { + fSettings.load(store); + } + public void save(ISettingsStore store) { + fSettings.save(store); + } + +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.java new file mode 100644 index 00000000000..77e83c3d748 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.serial; + +import org.eclipse.osgi.util.NLS; +public class SerialMessages extends NLS { + static { + NLS.initializeMessages(SerialMessages.class.getName(), SerialMessages.class); + } + public static String CONNTYPE_SERIAL; + public static String PROP_TITLE; + public static String PORT; + public static String BAUDRATE; + public static String DATABITS; + public static String STOPBITS; + public static String PARITY; + public static String FLOWCONTROL; + public static String PORT_IN_USE; + public static String TIMEOUT; + +} diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.properties b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.properties new file mode 100644 index 00000000000..2708d803517 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialMessages.properties @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2006 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: +# Wind River Systems, Inc. - initial implementation +# +############################################################################### +PORT_IN_USE = Serial port \''{0}\'' is currently in use\!\nDo you want to close the port? +CONNTYPE_SERIAL = Serial +PROP_TITLE = Terminal +PORT = Port +BAUDRATE = Baud Rate +DATABITS = Data Bits +STOPBITS = Stop Bits +PARITY = Parity +FLOWCONTROL = Flow Control +TIMEOUT = Timeout (sec) diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialPortHandler.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialPortHandler.java new file mode 100644 index 00000000000..c4b4a98cde6 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialPortHandler.java @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.serial; + +import java.io.IOException; +import java.text.MessageFormat; + +import javax.comm.CommPortOwnershipListener; +import javax.comm.SerialPortEvent; +import javax.comm.SerialPortEventListener; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; + +/** + * UNDER CONSTRUCTION + */ +public class SerialPortHandler implements + SerialPortEventListener, CommPortOwnershipListener { + /** + * + */ + private final ITerminalControl fControl; + private final SerialConnector fConn; + protected byte[] bytes = new byte[2048]; + + /** + * UNDER CONSTRUCTION + * @param control TODO + */ + public SerialPortHandler(SerialConnector conn,ITerminalControl control) { + super(); + fControl = control; + fConn=conn; + } + + // Message handlers + + /** + * UNDER CONSTRUCTION + */ + public void onSerialDataAvailable(Object data) { + try { + while (fConn.getInputStream() != null && fConn.getInputStream().available() > 0) { + int nBytes = fConn.getInputStream().read(bytes); + fControl.writeToTerminal(new String(bytes, 0, nBytes)); + } + } catch (IOException ex) { + fControl.displayTextInTerminal(ex.getMessage()); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + public void onSerialOwnershipRequested(Object data) { + if (fConn.isPortInUse()) { + fConn.setPortInUse(false); + return; + } + + Display.getDefault().asyncExec(new Runnable() { + public void run() { + String[] args = new String[] { fConn.getSerialSettings().getSerialPort() }; + String strMsg = MessageFormat.format(SerialMessages.PORT_IN_USE, args); + + if (!MessageDialog.openQuestion(fControl.getShell(), SerialMessages.PROP_TITLE, strMsg)) + return; + fControl.setState(TerminalState.CONNECTING); + } + + }); + } + + // SerialPortEventListener interface + public void serialEvent(SerialPortEvent event) { + switch (event.getEventType()) { + case SerialPortEvent.DATA_AVAILABLE: + onSerialDataAvailable(null); + break; + } + } + + // CommPortOwnershipListener interface + + /** + * UNDER CONSTRUCTION + */ + public void ownershipChange(int nType) { + switch (nType) { + case CommPortOwnershipListener.PORT_OWNERSHIP_REQUESTED: + onSerialOwnershipRequested(null); + break; + } + } +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialProperties.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialProperties.java new file mode 100644 index 00000000000..63d80c4b3ab --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialProperties.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.serial; + +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.Vector; + +import javax.comm.CommPortIdentifier; + +public class SerialProperties { + protected List fSerialPortTable; + protected List fBaudRateTable; + protected List fDataBitsTable; + protected List fStopBitsTable; + protected List fParityTable; + protected List fFlowControlTable; + protected String fDefaultConnType; + protected String fDefaultSerialPort; + protected String fDefaultBaudRate; + protected String fDefaultDataBits; + protected String fDefaultStopBits; + protected String fDefaultParity; + protected String fDefaultFlowControl; + + public SerialProperties() { + setupProperties(); + } + public List getSerialPortTable() { + return fSerialPortTable; + } + + public List getBaudRateTable() { + return fBaudRateTable; + } + + public List getDataBitsTable() { + return fDataBitsTable; + } + + public List getStopBitsTable() { + return fStopBitsTable; + } + + public List getParityTable() { + return fParityTable; + } + + public List getFlowControlTable() { + return fFlowControlTable; + } + public String getDefaultConnType() { + return fDefaultConnType; + } + + public String getDefaultSerialPort() { + return fDefaultSerialPort; + } + + public String getDefaultBaudRate() { + return fDefaultBaudRate; + } + + public String getDefaultDataBits() { + return fDefaultDataBits; + } + + public String getDefaultStopBits() { + return fDefaultStopBits; + } + + public String getDefaultParity() { + return fDefaultParity; + } + + public String getDefaultFlowControl() { + return fDefaultFlowControl; + } + public String getDefaultTimeout() { + return "5"; + } + protected void setupProperties() { + fSerialPortTable = new Vector(); + fBaudRateTable = new Vector(); + fDataBitsTable = new Vector(); + fStopBitsTable = new Vector(); + fParityTable = new Vector(); + fFlowControlTable = new Vector(); + fDefaultConnType = ""; //$NON-NLS-1$ + fDefaultSerialPort = ""; //$NON-NLS-1$ + fDefaultBaudRate = ""; //$NON-NLS-1$ + fDefaultDataBits = ""; //$NON-NLS-1$ + fDefaultStopBits = ""; //$NON-NLS-1$ + fDefaultParity = ""; //$NON-NLS-1$ + fDefaultFlowControl = ""; //$NON-NLS-1$ + + fBaudRateTable.add("300"); //$NON-NLS-1$ + fBaudRateTable.add("1200"); //$NON-NLS-1$ + fBaudRateTable.add("2400"); //$NON-NLS-1$ + fBaudRateTable.add("4800"); //$NON-NLS-1$ + fBaudRateTable.add("9600"); //$NON-NLS-1$ + fBaudRateTable.add("19200"); //$NON-NLS-1$ + fBaudRateTable.add("38400"); //$NON-NLS-1$ + fBaudRateTable.add("57600"); //$NON-NLS-1$ + fBaudRateTable.add("115200"); //$NON-NLS-1$ + + fDataBitsTable.add("5"); //$NON-NLS-1$ + fDataBitsTable.add("6"); //$NON-NLS-1$ + fDataBitsTable.add("7"); //$NON-NLS-1$ + fDataBitsTable.add("8"); //$NON-NLS-1$ + + fStopBitsTable.add("1"); //$NON-NLS-1$ + fStopBitsTable.add("1_5"); //$NON-NLS-1$ + fStopBitsTable.add("2"); //$NON-NLS-1$ + + fParityTable.add("None"); //$NON-NLS-1$ + fParityTable.add("Even"); //$NON-NLS-1$ + fParityTable.add("Odd"); //$NON-NLS-1$ + fParityTable.add("Mark"); //$NON-NLS-1$ + fParityTable.add("Space"); //$NON-NLS-1$ + + fFlowControlTable.add("None"); //$NON-NLS-1$ + fFlowControlTable.add("RTS/CTS"); //$NON-NLS-1$ + fFlowControlTable.add("Xon/Xoff"); //$NON-NLS-1$ + + fDefaultBaudRate = (String) fBaudRateTable.get(4); + fDefaultDataBits = (String) fDataBitsTable.get(3); + fDefaultStopBits = (String) fStopBitsTable.get(0); + fDefaultParity = (String) fParityTable.get(0); + fDefaultFlowControl = (String) fFlowControlTable.get(0); + + Enumeration portIdEnum= CommPortIdentifier.getPortIdentifiers();; + while (portIdEnum.hasMoreElements()) { + CommPortIdentifier identifier = (CommPortIdentifier) portIdEnum.nextElement(); + String strName = identifier.getName(); + int nPortType = identifier.getPortType(); + + if (nPortType == CommPortIdentifier.PORT_SERIAL) + fSerialPortTable.add(strName); + } + + Collections.sort(fSerialPortTable); + + if (!fSerialPortTable.isEmpty()) { + fDefaultSerialPort = (String) fSerialPortTable.get(0); + } + } +} diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettings.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettings.java new file mode 100644 index 00000000000..dc61203e140 --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettings.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.serial; + +import javax.comm.SerialPort; + +import org.eclipse.tm.terminal.ISettingsStore; +import org.eclipse.tm.terminal.ITerminalConnector; + +public class SerialSettings implements ISerialSettings { + protected String fSerialPort; + protected String fBaudRate; + protected String fDataBits; + protected String fStopBits; + protected String fParity; + protected String fFlowControl; + protected String fTimeout; + final private SerialProperties fProperties=new SerialProperties(); + + public String getSerialPort() { + return fSerialPort; + } + + public void setSerialPort(String strSerialPort) { + fSerialPort = strSerialPort; + } + + public String getBaudRateString() { + return fBaudRate; + } + + public int getBaudRate() { + int nBaudRate; + + try { + nBaudRate = Integer.parseInt(fBaudRate); + } catch (NumberFormatException numberFormatException) { + nBaudRate = 9600; + } + + return nBaudRate; + } + + public void setBaudRate(String strBaudRate) { + fBaudRate = strBaudRate; + } + + public String getDataBitsString() { + return fDataBits; + } + + public int getDataBits() { + if (fDataBits.equals("5")) { //$NON-NLS-1$ + return SerialPort.DATABITS_5; + } else if (fDataBits.equals("6")) { //$NON-NLS-1$ + return SerialPort.DATABITS_6; + } else if (fDataBits.equals("7")) { //$NON-NLS-1$ + return SerialPort.DATABITS_7; + } else { + return SerialPort.DATABITS_8; + } + } + + public void setDataBits(String strDataBits) { + fDataBits = strDataBits; + } + + public String getStopBitsString() { + return fStopBits; + } + + public int getStopBits() { + if (fStopBits.equals("1_5")) { //$NON-NLS-1$ + return SerialPort.STOPBITS_1_5; + } else if (fStopBits.equals("2")) { //$NON-NLS-1$ + return SerialPort.STOPBITS_2; + } else { // 1 + return SerialPort.STOPBITS_1; + } + } + + public void setStopBits(String strStopBits) { + fStopBits = strStopBits; + } + + public String getParityString() { + return fParity; + } + + public int getParity() { + if (fParity.equals("Even")) //$NON-NLS-1$ + { + return SerialPort.PARITY_EVEN; + } else if (fParity.equals("Odd")) //$NON-NLS-1$ + { + return SerialPort.PARITY_ODD; + } else if (fParity.equals("Mark")) //$NON-NLS-1$ + { + return SerialPort.PARITY_MARK; + } else if (fParity.equals("Space")) //$NON-NLS-1$ + { + return SerialPort.PARITY_SPACE; + } else // None + { + return SerialPort.PARITY_NONE; + } + } + + public void setParity(String strParity) { + fParity = strParity; + } + + public String getFlowControlString() { + return fFlowControl; + } + + public int getFlowControl() { + if (fFlowControl.equals("RTS/CTS")) //$NON-NLS-1$ + { + return SerialPort.FLOWCONTROL_RTSCTS_IN; + } else if (fFlowControl.equals("Xon/Xoff")) //$NON-NLS-1$ + { + return SerialPort.FLOWCONTROL_XONXOFF_IN; + } else // None + { + return SerialPort.FLOWCONTROL_NONE; + } + } + + public void setFlowControl(String strFlow) { + fFlowControl = strFlow; + } + + public String getStatusString(String strConnected) { + return " (" + //$NON-NLS-1$ + getSerialPort() + ", " + //$NON-NLS-1$ + getBaudRateString() + ", " + //$NON-NLS-1$ + getDataBitsString() + ", " + //$NON-NLS-1$ + getStopBitsString() + ", " + //$NON-NLS-1$ + getParityString() + ", " + //$NON-NLS-1$ + getFlowControlString() + " - " + //$NON-NLS-1$ + strConnected + ")"; //$NON-NLS-1$ + } + + public ITerminalConnector makeConnector() { + return new SerialConnector(this); + } + + public void load(ISettingsStore store) { + fSerialPort = store.get("SerialPort", fProperties.getDefaultSerialPort());//$NON-NLS-1$ + fBaudRate = store.get("BaudRate", fProperties.getDefaultBaudRate());//$NON-NLS-1$ + fDataBits = store.get("DataBits", fProperties.getDefaultDataBits());//$NON-NLS-1$ + fStopBits = store.get("StopBits", fProperties.getDefaultStopBits());//$NON-NLS-1$ + fParity = store.get("Parity", fProperties.getDefaultParity());//$NON-NLS-1$ + fFlowControl = store.get("FlowControl", fProperties.getDefaultFlowControl());//$NON-NLS-1$ + fTimeout = store.get("Timeout",fProperties.getDefaultTimeout()); + } + + public void save(ISettingsStore store) { + store.put("SerialPort", fSerialPort); //$NON-NLS-1$ + store.put("BaudRate", fBaudRate); //$NON-NLS-1$ + store.put("DataBits", fDataBits); //$NON-NLS-1$ + store.put("StopBits", fStopBits); //$NON-NLS-1$ + store.put("Parity", fParity); //$NON-NLS-1$ + store.put("FlowControl", fFlowControl); //$NON-NLS-1$ + } + + public SerialProperties getProperties() { + return fProperties; + } + + public int getTimeout() { + try { + return Integer.parseInt(fTimeout); + } catch (NumberFormatException numberFormatException) { + return 10; + } + } + public String getTimeoutString() { + return fTimeout; + } + + public void setTimeout(String timeout) { + fTimeout = timeout; + } +} diff --git a/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettingsPage.java b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettingsPage.java new file mode 100644 index 00000000000..01504d9a5fc --- /dev/null +++ b/org.eclipse.tm.terminal.serial/src/org/eclipse/tm/terminal/internal/serial/SerialSettingsPage.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.serial; + +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.terminal.ISettingsPage; + +public class SerialSettingsPage implements ISettingsPage { + private Combo fSerialPortCombo; + private Combo fBaudRateCombo; + private Combo fDataBitsCombo; + private Combo fStopBitsCombo; + private Combo fParityCombo; + private Combo fFlowControlCombo; + private Text fTimeout; + private final SerialSettings fTerminalSettings; + + public SerialSettingsPage(SerialSettings settings) { + fTerminalSettings=settings; + } + public void saveSettings() { + fTerminalSettings.setSerialPort(getComboValue(fSerialPortCombo)); + fTerminalSettings.setBaudRate(getComboValue(fBaudRateCombo)); + fTerminalSettings.setDataBits(getComboValue(fDataBitsCombo)); + fTerminalSettings.setStopBits(getComboValue(fStopBitsCombo)); + fTerminalSettings.setParity(getComboValue(fParityCombo)); + fTerminalSettings.setFlowControl(getComboValue(fFlowControlCombo)); + fTerminalSettings.setTimeout(fTimeout.getText()); + } + public void loadSettings() { + // Load controls + SerialProperties properties = fTerminalSettings.getProperties(); + List list; + + list = properties.getSerialPortTable(); + loadCombo(fSerialPortCombo, list); + + list = properties.getBaudRateTable(); + loadCombo(fBaudRateCombo, list); + + list = properties.getDataBitsTable(); + loadCombo(fDataBitsCombo, list); + + list = properties.getStopBitsTable(); + loadCombo(fStopBitsCombo, list); + + list = properties.getParityTable(); + loadCombo(fParityCombo, list); + + list = properties.getFlowControlTable(); + loadCombo(fFlowControlCombo, list); + + setCombo(fSerialPortCombo,fTerminalSettings.getSerialPort()); + setCombo(fBaudRateCombo,fTerminalSettings.getBaudRateString()); + setCombo(fDataBitsCombo,fTerminalSettings.getDataBitsString()); + setCombo(fStopBitsCombo,fTerminalSettings.getStopBitsString()); + setCombo(fParityCombo,fTerminalSettings.getParityString()); + setCombo(fFlowControlCombo,fTerminalSettings.getFlowControlString()); + fTimeout.setText(fTerminalSettings.getTimeoutString()); + } + private void setCombo(Combo combo,String value) { + if(value==null) + return; + int nIndex = combo.indexOf(value); + if (nIndex == -1) + return; + + combo.select(nIndex); + + } + private String getComboValue(Combo combo) { + int nIndex = combo.getSelectionIndex(); + if (nIndex == -1) + return ""; //$NON-NLS-1$ + + return combo.getItem(nIndex); + + } + public boolean validateSettings() { + return true; + } + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(2, false); + + composite.setLayout(gridLayout); + composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + fSerialPortCombo=addLabeledCombo(composite, SerialMessages.PORT + ":"); + fBaudRateCombo=addLabeledCombo(composite, SerialMessages.BAUDRATE + ":"); //$NON-NLS-1$ + fDataBitsCombo=addLabeledCombo(composite, SerialMessages.DATABITS + ":"); //$NON-NLS-1$ + fStopBitsCombo=addLabeledCombo(composite, SerialMessages.STOPBITS + ":"); //$NON-NLS-1$ + fParityCombo=addLabeledCombo(composite, SerialMessages.PARITY + ":"); //$NON-NLS-1$ + fFlowControlCombo=addLabeledCombo(composite, SerialMessages.FLOWCONTROL + ":"); //$NON-NLS-1$ + + new Label(composite, SWT.RIGHT).setText(SerialMessages.TIMEOUT + ":"); //$NON-NLS-1$ + fTimeout = new Text(composite, SWT.BORDER); + fTimeout.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + loadSettings(); + } + + private Combo addLabeledCombo(Composite composite, String label) { + new Label(composite, SWT.RIGHT).setText(label); + Combo combo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY); + combo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + return combo; + } + private void loadCombo(Combo ctlCombo, List table) { + for (Iterator iter = table.iterator(); iter.hasNext();) { + String label = (String) iter.next(); + ctlCombo.add(label); + } + } + + public String getName() { + return SerialMessages.CONNTYPE_SERIAL; + } +} diff --git a/org.eclipse.tm.terminal.view-feature/.project b/org.eclipse.tm.terminal.view-feature/.project new file mode 100644 index 00000000000..57ff3d8e631 --- /dev/null +++ b/org.eclipse.tm.terminal.view-feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.view-feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/org.eclipse.tm.terminal.view-feature/build.properties b/org.eclipse.tm.terminal.view-feature/build.properties new file mode 100644 index 00000000000..64f93a9f0b7 --- /dev/null +++ b/org.eclipse.tm.terminal.view-feature/build.properties @@ -0,0 +1 @@ +bin.includes = feature.xml diff --git a/org.eclipse.tm.terminal.view-feature/feature.xml b/org.eclipse.tm.terminal.view-feature/feature.xml new file mode 100644 index 00000000000..bae89b9b85b --- /dev/null +++ b/org.eclipse.tm.terminal.view-feature/feature.xml @@ -0,0 +1,33 @@ + + + + + [Enter Feature Description here.] + + + + [Enter Copyright Description here.] + + + + [Enter License Description here.] + + + + + + + + + + + diff --git a/org.eclipse.tm.terminal.view/.classpath b/org.eclipse.tm.terminal.view/.classpath new file mode 100644 index 00000000000..ce73933404a --- /dev/null +++ b/org.eclipse.tm.terminal.view/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/org.eclipse.tm.terminal.view/.project b/org.eclipse.tm.terminal.view/.project new file mode 100644 index 00000000000..8e57f57b452 --- /dev/null +++ b/org.eclipse.tm.terminal.view/.project @@ -0,0 +1,34 @@ + + + org.eclipse.tm.terminal.view + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + net.sourceforge.metrics.builder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + net.sourceforge.metrics.nature + + diff --git a/org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..b2cf7ff9c9c --- /dev/null +++ b/org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +#Thu Nov 30 06:15:17 CET 2006 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2 +org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.source=1.3 diff --git a/org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..9a20fca52a4 --- /dev/null +++ b/org.eclipse.tm.terminal.view/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +#Mon Jul 31 14:55:17 CEST 2006 +eclipse.preferences.version=1 +internal.default.compliance=user diff --git a/org.eclipse.tm.terminal.view/META-INF/MANIFEST.MF b/org.eclipse.tm.terminal.view/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..6a94941e046 --- /dev/null +++ b/org.eclipse.tm.terminal.view/META-INF/MANIFEST.MF @@ -0,0 +1,13 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.view;singleton:=true +Bundle-Version: 0.9.0 +Bundle-Activator: org.eclipse.tm.terminal.internal.view.TerminalViewPlugin +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.tm.terminal +Eclipse-LazyStart: true +Bundle-RequiredExecutionEnvironment: J2SE-1.4 +Bundle-Vendor: %providerName diff --git a/org.eclipse.tm.terminal.view/build.properties b/org.eclipse.tm.terminal.view/build.properties new file mode 100644 index 00000000000..64a3723302a --- /dev/null +++ b/org.eclipse.tm.terminal.view/build.properties @@ -0,0 +1,17 @@ +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + icons/,\ + .settings/,\ + plugin.properties +src.includes = .classpath,\ + .project,\ + .settings/,\ + META-INF/,\ + build.properties,\ + icons/,\ + plugin.properties,\ + plugin.xml,\ + src/ diff --git a/org.eclipse.tm.terminal/icons/clcl16/connect_co.gif b/org.eclipse.tm.terminal.view/icons/clcl16/connect_co.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/clcl16/connect_co.gif rename to org.eclipse.tm.terminal.view/icons/clcl16/connect_co.gif diff --git a/org.eclipse.tm.terminal/icons/clcl16/disconnect_co.gif b/org.eclipse.tm.terminal.view/icons/clcl16/disconnect_co.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/clcl16/disconnect_co.gif rename to org.eclipse.tm.terminal.view/icons/clcl16/disconnect_co.gif diff --git a/org.eclipse.tm.terminal/icons/clcl16/newterminal.gif b/org.eclipse.tm.terminal.view/icons/clcl16/newterminal.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/clcl16/newterminal.gif rename to org.eclipse.tm.terminal.view/icons/clcl16/newterminal.gif diff --git a/org.eclipse.tm.terminal/icons/clcl16/properties_tsk.gif b/org.eclipse.tm.terminal.view/icons/clcl16/properties_tsk.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/clcl16/properties_tsk.gif rename to org.eclipse.tm.terminal.view/icons/clcl16/properties_tsk.gif diff --git a/org.eclipse.tm.terminal/icons/cview16/terminal_view.gif b/org.eclipse.tm.terminal.view/icons/cview16/terminal_view.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/cview16/terminal_view.gif rename to org.eclipse.tm.terminal.view/icons/cview16/terminal_view.gif diff --git a/org.eclipse.tm.terminal/icons/dlcl16/connect_co.gif b/org.eclipse.tm.terminal.view/icons/dlcl16/connect_co.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/dlcl16/connect_co.gif rename to org.eclipse.tm.terminal.view/icons/dlcl16/connect_co.gif diff --git a/org.eclipse.tm.terminal/icons/dlcl16/disconnect_co.gif b/org.eclipse.tm.terminal.view/icons/dlcl16/disconnect_co.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/dlcl16/disconnect_co.gif rename to org.eclipse.tm.terminal.view/icons/dlcl16/disconnect_co.gif diff --git a/org.eclipse.tm.terminal/icons/dlcl16/newterminal.gif b/org.eclipse.tm.terminal.view/icons/dlcl16/newterminal.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/dlcl16/newterminal.gif rename to org.eclipse.tm.terminal.view/icons/dlcl16/newterminal.gif diff --git a/org.eclipse.tm.terminal/icons/dlcl16/properties_tsk.gif b/org.eclipse.tm.terminal.view/icons/dlcl16/properties_tsk.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/dlcl16/properties_tsk.gif rename to org.eclipse.tm.terminal.view/icons/dlcl16/properties_tsk.gif diff --git a/org.eclipse.tm.terminal/icons/elcl16/connect_co.gif b/org.eclipse.tm.terminal.view/icons/elcl16/connect_co.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/elcl16/connect_co.gif rename to org.eclipse.tm.terminal.view/icons/elcl16/connect_co.gif diff --git a/org.eclipse.tm.terminal/icons/elcl16/disconnect_co.gif b/org.eclipse.tm.terminal.view/icons/elcl16/disconnect_co.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/elcl16/disconnect_co.gif rename to org.eclipse.tm.terminal.view/icons/elcl16/disconnect_co.gif diff --git a/org.eclipse.tm.terminal/icons/elcl16/newterminal.gif b/org.eclipse.tm.terminal.view/icons/elcl16/newterminal.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/elcl16/newterminal.gif rename to org.eclipse.tm.terminal.view/icons/elcl16/newterminal.gif diff --git a/org.eclipse.tm.terminal/icons/elcl16/properties_tsk.gif b/org.eclipse.tm.terminal.view/icons/elcl16/properties_tsk.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/elcl16/properties_tsk.gif rename to org.eclipse.tm.terminal.view/icons/elcl16/properties_tsk.gif diff --git a/org.eclipse.tm.terminal/icons/eview16/terminal_view.gif b/org.eclipse.tm.terminal.view/icons/eview16/terminal_view.gif similarity index 100% rename from org.eclipse.tm.terminal/icons/eview16/terminal_view.gif rename to org.eclipse.tm.terminal.view/icons/eview16/terminal_view.gif diff --git a/org.eclipse.tm.terminal.view/plugin.properties b/org.eclipse.tm.terminal.view/plugin.properties new file mode 100644 index 00000000000..4c668735b62 --- /dev/null +++ b/org.eclipse.tm.terminal.view/plugin.properties @@ -0,0 +1,17 @@ +########################################################################## +# Copyright 2004 Wind River Systems, Inc. All rights reserved. +########################################################################## + +pluginName = Terminal View +providerName = Eclipse.org +terminal.views.category.name = Terminal +terminal.views.view.name = Terminal +terminal.views.view.font.description = The font for the terminal console. +terminal.views.view.font.label = Terminal Console Font + +terminal.view.context.name=Terminal view context +terminal.view.context.description=control-q override + +terminal.view.insertion.description=Terminal view insertion +terminal.view.insertion.name=Terminal view insert +terminal.view.insertion.category.name=Terminal view commands diff --git a/org.eclipse.tm.terminal.view/plugin.xml b/org.eclipse.tm.terminal.view/plugin.xml new file mode 100644 index 00000000000..ca523016721 --- /dev/null +++ b/org.eclipse.tm.terminal.view/plugin.xml @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + + + %terminal.views.view.font.description + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.java new file mode 100644 index 00000000000..193de4170a5 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.osgi.util.NLS; + +public class ActionMessages extends NLS { + static { + NLS.initializeMessages(ActionMessages.class.getName(), ActionMessages.class); + } + public static String NEW_TERMINAL; + public static String CONNECT; + public static String DISCONNECT; + public static String SETTINGS_ELLIPSE; + public static String COPY; + public static String CUT; + public static String PASTE; + public static String SELECTALL; + public static String CLEARALL; + public static String SETTINGS; + +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.properties b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.properties new file mode 100644 index 00000000000..faad8ee0e33 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/ActionMessages.properties @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2006 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: +# Wind River Systems, Inc. - initial implementation +# +############################################################################### +NEW_TERMINAL = New Terminal +CONNECT = Connect +DISCONNECT = Disconnect +SETTINGS_ELLIPSE = Settings... +COPY = Copy +CUT = Cut +PASTE = Paste +SELECTALL = Select All +CLEARALL = Clear All +SETTINGS = Settings diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalAction.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalAction.java new file mode 100644 index 00000000000..cd8fe30110f --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalAction.java @@ -0,0 +1,67 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + + +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.terminal.internal.view.ITerminalView; +import org.eclipse.tm.terminal.internal.view.TerminalViewPlugin; + +abstract public class TerminalAction extends Action { + protected final ITerminalView fTarget; + public TerminalAction(ITerminalView target, String strId) { + super(""); //$NON-NLS-1$ + + fTarget = target; + + setId(strId); + } + abstract public void run(); + protected void setupAction(String strText, String strToolTip, + String strImage, String strEnabledImage, String strDisabledImage, + boolean bEnabled) { + TerminalViewPlugin plugin; + ImageRegistry imageRegistry; + + plugin = TerminalViewPlugin.getDefault(); + imageRegistry = plugin.getImageRegistry(); + setupAction(strText, strToolTip, strImage, strEnabledImage, + strDisabledImage, bEnabled, imageRegistry); + } + protected void setupAction(String strText, String strToolTip, + String strImage, String strEnabledImage, String strDisabledImage, + boolean bEnabled, ImageRegistry imageRegistry) { + ImageDescriptor imageDescriptor; + + setText(strText); + setToolTipText(strToolTip); + setEnabled(bEnabled); + + imageDescriptor = imageRegistry.getDescriptor(strEnabledImage); + if (imageDescriptor != null) { + setImageDescriptor(imageDescriptor); + } + + imageDescriptor = imageRegistry.getDescriptor(strDisabledImage); + if (imageDescriptor != null) { + setDisabledImageDescriptor(imageDescriptor); + } + + imageDescriptor = imageRegistry.getDescriptor(strImage); + if (imageDescriptor != null) { + setHoverImageDescriptor(imageDescriptor); + } + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionClearAll.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionClearAll.java similarity index 72% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionClearAll.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionClearAll.java index 889715198e7..508e9791b8c 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionClearAll.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionClearAll.java @@ -12,23 +12,28 @@ *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.tm.terminal.internal.view.ITerminalView; public class TerminalActionClearAll extends TerminalAction { - protected TerminalActionClearAll(TerminalTarget target) + public TerminalActionClearAll(ITerminalView target) { super(target, - ON_EDIT_CLEARALL, TerminalActionClearAll.class.getName()); - setupAction(TERMINAL_TEXT_CLEARALL, - TERMINAL_TEXT_CLEARALL, + setupAction(ActionMessages.CLEARALL, + ActionMessages.CLEARALL, null, null, null, false); } + + public void run() { + fTarget.onEditClearAll(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionConnect.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionConnect.java similarity index 58% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionConnect.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionConnect.java index 078338e1c34..a892612a673 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionConnect.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionConnect.java @@ -11,21 +11,26 @@ *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.tm.terminal.internal.view.ITerminalView; +import org.eclipse.tm.terminal.internal.view.ImageConsts; public class TerminalActionConnect extends TerminalAction { - protected TerminalActionConnect(TerminalTarget target) + public TerminalActionConnect(ITerminalView target) { super(target, - ON_TERMINAL_CONNECT, TerminalActionConnect.class.getName()); - setupAction(TERMINAL_TEXT_CONNECT, - TERMINAL_TEXT_CONNECT, - TERMINAL_IMAGE_CLCL_CONNECT, - TERMINAL_IMAGE_ELCL_CONNECT, - TERMINAL_IMAGE_DLCL_CONNECT, + setupAction(ActionMessages.CONNECT, + ActionMessages.CONNECT, + ImageConsts.IMAGE_CLCL_CONNECT, + ImageConsts.IMAGE_ELCL_CONNECT, + ImageConsts.IMAGE_DLCL_CONNECT, true); } + public void run() { + fTarget.onTerminalConnect(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionCopy.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionCopy.java similarity index 79% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionCopy.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionCopy.java index 47c900f8a11..90122aa6ef7 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionCopy.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionCopy.java @@ -10,29 +10,32 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.terminal.internal.view.ITerminalView; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.internal.WorkbenchImages; public class TerminalActionCopy extends TerminalAction { - protected TerminalActionCopy(TerminalTarget target) + public TerminalActionCopy(ITerminalView target) { super(target, - ON_EDIT_COPY, TerminalActionCopy.class.getName()); ImageRegistry imageRegistry; imageRegistry = WorkbenchImages.getImageRegistry(); - setupAction(TERMINAL_TEXT_COPY, - TERMINAL_TEXT_COPY, + setupAction(ActionMessages.COPY, + ActionMessages.COPY, ISharedImages.IMG_TOOL_COPY, ISharedImages.IMG_TOOL_COPY, ISharedImages.IMG_TOOL_COPY_DISABLED, true, imageRegistry); } + public void run() { + fTarget.onEditCopy(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionCut.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionCut.java similarity index 80% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionCut.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionCut.java index 2a06c87748d..997b0675a0c 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionCut.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionCut.java @@ -10,29 +10,32 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.terminal.internal.view.ITerminalView; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.internal.WorkbenchImages; public class TerminalActionCut extends TerminalAction { - protected TerminalActionCut(TerminalTarget target) + public TerminalActionCut(ITerminalView target) { super(target, - ON_EDIT_CUT, TerminalActionCut.class.getName()); ImageRegistry imageRegistry; imageRegistry = WorkbenchImages.getImageRegistry(); - setupAction(TERMINAL_TEXT_CUT, - TERMINAL_TEXT_CUT, + setupAction(ActionMessages.CUT, + ActionMessages.CUT, ISharedImages.IMG_TOOL_CUT, ISharedImages.IMG_TOOL_CUT, ISharedImages.IMG_TOOL_CUT_DISABLED, true, imageRegistry); } + public void run() { + fTarget.onEditCut(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionDisconnect.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionDisconnect.java similarity index 58% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionDisconnect.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionDisconnect.java index e1f294da96e..d717a988b39 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionDisconnect.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionDisconnect.java @@ -10,24 +10,29 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.tm.terminal.internal.view.ITerminalView; +import org.eclipse.tm.terminal.internal.view.ImageConsts; public class TerminalActionDisconnect extends TerminalAction { /** * */ - protected TerminalActionDisconnect(TerminalTarget target) + public TerminalActionDisconnect(ITerminalView target) { super(target, - ON_TERMINAL_DISCONNECT, TerminalActionDisconnect.class.getName()); - setupAction(TERMINAL_TEXT_DISCONNECT, - TERMINAL_TEXT_DISCONNECT, - TERMINAL_IMAGE_CLCL_DISCONNECT, - TERMINAL_IMAGE_ELCL_DISCONNECT, - TERMINAL_IMAGE_DLCL_DISCONNECT, + setupAction(ActionMessages.DISCONNECT, + ActionMessages.DISCONNECT, + ImageConsts.IMAGE_CLCL_DISCONNECT, + ImageConsts.IMAGE_ELCL_DISCONNECT, + ImageConsts.IMAGE_DLCL_DISCONNECT, false); } + public void run() { + fTarget.onTerminalDisconnect(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionNewTerminal.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionNewTerminal.java similarity index 56% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionNewTerminal.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionNewTerminal.java index 80bfdccadb6..a0c0a49322c 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionNewTerminal.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionNewTerminal.java @@ -10,7 +10,10 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.tm.terminal.internal.view.ITerminalView; +import org.eclipse.tm.terminal.internal.view.ImageConsts; /** * UNDER CONSTRUCTION @@ -22,15 +25,18 @@ public class TerminalActionNewTerminal extends TerminalAction /** * UNDER CONSTRUCTION */ - protected TerminalActionNewTerminal(TerminalTarget target) + public TerminalActionNewTerminal(ITerminalView target) { - super(target, ON_TERMINAL_NEW_TERMINAL, TerminalActionNewTerminal.class.getName()); + super(target, TerminalActionNewTerminal.class.getName()); - setupAction(TERMINAL_TEXT_NEW_TERMINAL, - TERMINAL_TEXT_NEW_TERMINAL, - TERMINAL_IMAGE_NEW_TERMINAL, - TERMINAL_IMAGE_NEW_TERMINAL, - TERMINAL_IMAGE_NEW_TERMINAL, + setupAction(ActionMessages.NEW_TERMINAL, + ActionMessages.NEW_TERMINAL, + ImageConsts.IMAGE_NEW_TERMINAL, + ImageConsts.IMAGE_NEW_TERMINAL, + ImageConsts.IMAGE_NEW_TERMINAL, true); } + public void run() { + fTarget.onTerminalNewTerminal(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionPaste.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionPaste.java similarity index 79% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionPaste.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionPaste.java index 6d14e5612dd..b6b3de56b2e 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionPaste.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionPaste.java @@ -10,29 +10,32 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.terminal.internal.view.ITerminalView; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.internal.WorkbenchImages; public class TerminalActionPaste extends TerminalAction { - protected TerminalActionPaste(TerminalTarget target) + public TerminalActionPaste(ITerminalView target) { super(target, - ON_EDIT_PASTE, TerminalActionPaste.class.getName()); ImageRegistry imageRegistry; imageRegistry = WorkbenchImages.getImageRegistry(); - setupAction(TERMINAL_TEXT_PASTE, - TERMINAL_TEXT_PASTE, + setupAction(ActionMessages.PASTE, + ActionMessages.PASTE, ISharedImages.IMG_TOOL_PASTE, ISharedImages.IMG_TOOL_PASTE_DISABLED, ISharedImages.IMG_TOOL_PASTE, false, imageRegistry); } + public void run() { + fTarget.onEditPaste(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionSelectAll.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionSelectAll.java similarity index 72% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionSelectAll.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionSelectAll.java index 19903bda345..4c0d62e9cc5 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionSelectAll.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionSelectAll.java @@ -10,21 +10,25 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.tm.terminal.internal.view.ITerminalView; public class TerminalActionSelectAll extends TerminalAction { - protected TerminalActionSelectAll(TerminalTarget target) + public TerminalActionSelectAll(ITerminalView target) { super(target, - ON_EDIT_SELECTALL, TerminalActionSelectAll.class.getName()); - setupAction(TERMINAL_TEXT_SELECTALL, - TERMINAL_TEXT_SELECTALL, + setupAction(ActionMessages.SELECTALL, + ActionMessages.SELECTALL, null, null, null, false); } + public void run() { + fTarget.onEditSelectAll(); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionSettings.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionSettings.java similarity index 57% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionSettings.java rename to org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionSettings.java index b0389b62cb1..a86f09e334a 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalActionSettings.java +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/actions/TerminalActionSettings.java @@ -10,21 +10,26 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.actions; + +import org.eclipse.tm.terminal.internal.view.ITerminalView; +import org.eclipse.tm.terminal.internal.view.ImageConsts; public class TerminalActionSettings extends TerminalAction { - protected TerminalActionSettings(TerminalTarget target) + public TerminalActionSettings(ITerminalView target) { super(target, - ON_TERMINAL_SETTINGS, TerminalActionSettings.class.getName()); - setupAction(TERMINAL_TEXT_SETTINGS_ELLIPSE, - TERMINAL_TEXT_SETTINGS, - TERMINAL_IMAGE_CLCL_SETTINGS, - TERMINAL_IMAGE_ELCL_SETTINGS, - TERMINAL_IMAGE_DLCL_SETTINGS, + setupAction(ActionMessages.SETTINGS_ELLIPSE, + ActionMessages.SETTINGS, + ImageConsts.IMAGE_CLCL_SETTINGS, + ImageConsts.IMAGE_ELCL_SETTINGS, + ImageConsts.IMAGE_DLCL_SETTINGS, true); } + public void run() { + fTarget.onTerminalSettings(); + } } diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ITerminalView.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ITerminalView.java new file mode 100644 index 00000000000..cdbf0603d90 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ITerminalView.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.view; + +public interface ITerminalView { + + /** + * Display a new Terminal view. This method is called when the user clicks the New + * Terminal button in any Terminal view's toolbar. + */ + public void onTerminalNewTerminal(); + public void onTerminalConnect(); + public void onTerminalDisconnect(); + public void onTerminalSettings(); + public void onTerminalFontChanged(); + public void onEditCopy(); + public void onEditCut(); + public void onEditPaste(); + public void onEditClearAll(); + public void onEditSelectAll(); +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ImageConsts.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ImageConsts.java new file mode 100644 index 00000000000..c531dcb83dc --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ImageConsts.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.view; + +public interface ImageConsts +{ + public final static String IMAGE_DIR_ROOT = "icons/"; //$NON-NLS-1$ + public final static String IMAGE_DIR_CTOOL = "ctool16/"; // basic colors - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_LOCALTOOL = "clcl16/"; // basic colors - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_DLCL = "dlcl16/"; // disabled - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_ELCL = "elcl16/"; // enabled - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_OBJECT = "obj16/"; // basic colors - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_WIZBAN = "wizban/"; // basic colors - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_OVR = "ovr16/"; // basic colors - size 7x8 //$NON-NLS-1$ + public final static String IMAGE_DIR_VIEW = "cview16/"; // views //$NON-NLS-1$ + public final static String IMAGE_DIR_EVIEW = "eview16/"; // views //$NON-NLS-1$ + + public static final String IMAGE_NEW_TERMINAL = "TerminalViewNewTerminal"; //$NON-NLS-1$ + public static final String IMAGE_CLCL_CONNECT = "ImageClclConnect"; //$NON-NLS-1$ + public static final String IMAGE_CLCL_DISCONNECT = "ImageClclDisconnect"; //$NON-NLS-1$ + public static final String IMAGE_CLCL_SETTINGS = "ImageClclSettings"; //$NON-NLS-1$ + + public static final String IMAGE_DLCL_CONNECT = "ImageDlclConnect"; //$NON-NLS-1$ + public static final String IMAGE_DLCL_DISCONNECT = "ImageDlclDisconnect"; //$NON-NLS-1$ + public static final String IMAGE_DLCL_SETTINGS = "ImageDlclSettings"; //$NON-NLS-1$ + + public static final String IMAGE_ELCL_CONNECT = "ImageElclConnect"; //$NON-NLS-1$ + public static final String IMAGE_ELCL_DISCONNECT = "ImageElclDisconnect"; //$NON-NLS-1$ + public static final String IMAGE_ELCL_SETTINGS = "ImageElclSettings"; //$NON-NLS-1$ + } diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/PageBook.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/PageBook.java new file mode 100644 index 00000000000..96b4f41d7cd --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/PageBook.java @@ -0,0 +1,113 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Layout; + +/** + * A pagebook is a composite control where only a single control is visible + * at a time. It is similar to a notebook, but without tabs. + *

+ * This class may be instantiated; it is not intended to be subclassed. + *

+ * + */ +public class PageBook extends Composite { + private Point minimumPageSize = new Point(0, 0); + /** + * Layout for the page container. + * + */ + private class PageLayout extends Layout { + public Point computeSize(Composite composite, int wHint, int hHint, boolean force) { + if (wHint != SWT.DEFAULT && hHint != SWT.DEFAULT) + return new Point(wHint, hHint); + int x = minimumPageSize.x; + int y = minimumPageSize.y; + Control[] children = composite.getChildren(); + for (int i = 0; i < children.length; i++) { + Point size = children[i].computeSize(SWT.DEFAULT, SWT.DEFAULT, force); + x = Math.max(x, size.x); + y = Math.max(y, size.y); + } + + if (wHint != SWT.DEFAULT) + x = wHint; + if (hHint != SWT.DEFAULT) + y = hHint; + return new Point(x, y); + } + + public void layout(Composite composite, boolean force) { + Rectangle rect = composite.getClientArea(); + Control[] children = composite.getChildren(); + for (int i = 0; i < children.length; i++) { + children[i].setSize(rect.width, rect.height); + } + } + } + /** + * Creates a new empty pagebook. + * + * @param parent the parent composite + * @param style the SWT style bits (use {@link SWT#NONE}) + */ + public PageBook(Composite parent, int style) { + super(parent, style); + setLayout(new PageLayout()); + } + /** + * The current control; null if none. + */ + private Control currentPage = null; + + /** + * Shows the given page. This method has no effect if the given page is not + * contained in this pagebook. + * + * @param page the page to show + */ + public void showPage(Control page) { + + if (page == currentPage) + return; + if (page.getParent() != this) + return; + + currentPage = page; + + // show new page + if (page != null) { + if (!page.isDisposed()) { + page.setVisible(true); + layout(true); + // if (fRequestFocusOnShowPage) + // page.setFocus(); + } + } + + // hide old *after* new page has been made visible in order to avoid flashing + // we have to hide all other pages, because they might be visible + // by some other means... + Control[] pages=getChildren(); + for (int i = 0; i < pages.length; i++) { + if(pages[i]!=page && !pages[i].isDisposed()) { + pages[i].setVisible(false); + } + } + } +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingStorePrefixDecorator.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingStorePrefixDecorator.java new file mode 100644 index 00000000000..e305e0a4ea8 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingStorePrefixDecorator.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.tm.terminal.ISettingsStore; + +public class SettingStorePrefixDecorator implements ISettingsStore { + private final String fPrefix; + private final ISettingsStore fStore; + SettingStorePrefixDecorator(ISettingsStore store,String prefix) { + fPrefix=prefix; + fStore=store; + } + public String get(String key) { + return fStore.get(fPrefix+key); + } + + public String get(String key, String defaultValue) { + return fStore.get(fPrefix+key,defaultValue); + } + + public void put(String key, String value) { + fStore.put(fPrefix+key,value); + } + +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingsStore.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingsStore.java new file mode 100644 index 00000000000..ee715a4a54e --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/SettingsStore.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.tm.terminal.ISettingsStore; + +/** + * + * A {@link IDialogSettings} based {@link ISettingsStore}. + * + * @author Michael Scharf + */ +class SettingsStore implements ISettingsStore { + final private IDialogSettings fDialogSettings; + final private String fPrefix; + public SettingsStore(String terminalPartName) { + fDialogSettings=TerminalViewPlugin.getDefault().getDialogSettings(); + fPrefix=getClass().getName() + "." + terminalPartName + "."; //$NON-NLS-1$ //$NON-NLS-2$; + } + + public String get(String key) { + return get(key,null); + } + public String get(String key, String defaultValue) { + String value = fDialogSettings.get(fPrefix + key); + + if ((value == null) || (value.equals(""))) //$NON-NLS-1$ + return defaultValue; + + return value; + } + + public void put(String key, String strValue) { + fDialogSettings.put(fPrefix + key , strValue); + } +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalPreferencePage.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalPreferencePage.java new file mode 100644 index 00000000000..dddcdb38f82 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalPreferencePage.java @@ -0,0 +1,150 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.IntegerFieldEditor; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +public class TerminalPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + public static final String PREF_LIMITOUTPUT = "TerminalPrefLimitOutput"; //$NON-NLS-1$ + public static final String PREF_BUFFERLINES = "TerminalPrefBufferLines"; //$NON-NLS-1$ + public static final String PREF_TIMEOUT_SERIAL = "TerminalPrefTimeoutSerial"; //$NON-NLS-1$ + public static final String PREF_TIMEOUT_NETWORK = "TerminalPrefTimeoutNetwork"; //$NON-NLS-1$ + public static final boolean DEFAULT_LIMITOUTPUT = true; + public static final int DEFAULT_BUFFERLINES = 1000; + public static final int DEFAULT_TIMEOUT_SERIAL = 5; + public static final int DEFAULT_TIMEOUT_NETWORK = 5; + + + protected TerminalBooleanFieldEditor fEditorLimitOutput; + + protected IntegerFieldEditor fEditorBufferSize; + + protected IntegerFieldEditor fEditorSerialTimeout; + + protected IntegerFieldEditor fEditorNetworkTimeout; + public TerminalPreferencePage() { + super(GRID); + } + public void onLimitOutputSelected() { + Button ctlButton; + Text ctlText; + Label ctlLabel; + boolean bEnabled; + + ctlButton = fEditorLimitOutput.getChangeControl(getFieldEditorParent()); + ctlText = fEditorBufferSize.getTextControl(getFieldEditorParent()); + ctlLabel = fEditorBufferSize.getLabelControl(getFieldEditorParent()); + bEnabled = ctlButton.getSelection(); + + ctlText.setEnabled(bEnabled); + ctlLabel.setEnabled(bEnabled); + } + protected void createFieldEditors() { + setupPage(); + } + protected void initialize() { + super.initialize(); + + onLimitOutputSelected(); + } + protected void performDefaults() { + super.performDefaults(); + + onLimitOutputSelected(); + } + public void init(IWorkbench workbench) { + // do nothing + } + protected void setupPage() { + setupData(); + setupEditors(); + setupListeners(); + } + protected void setupData() { + TerminalViewPlugin plugin; + IPreferenceStore preferenceStore; + + plugin = TerminalViewPlugin.getDefault(); + preferenceStore = plugin.getPreferenceStore(); + setPreferenceStore(preferenceStore); + } + protected void setupEditors() { + fEditorLimitOutput = new TerminalBooleanFieldEditor( + PREF_LIMITOUTPUT, ViewMessages.LIMITOUTPUT, + getFieldEditorParent()); + fEditorBufferSize = new IntegerFieldEditor(PREF_BUFFERLINES, + ViewMessages.BUFFERLINES, getFieldEditorParent()); + fEditorSerialTimeout = new IntegerFieldEditor( + PREF_TIMEOUT_SERIAL, ViewMessages.SERIALTIMEOUT, + getFieldEditorParent()); + fEditorNetworkTimeout = new IntegerFieldEditor( + PREF_TIMEOUT_NETWORK, ViewMessages.NETWORKTIMEOUT, + getFieldEditorParent()); + + fEditorBufferSize.setValidRange(0, Integer.MAX_VALUE); + fEditorSerialTimeout.setValidRange(0, Integer.MAX_VALUE); + fEditorNetworkTimeout.setValidRange(0, Integer.MAX_VALUE); + + addField(fEditorLimitOutput); + addField(fEditorBufferSize); + addField(fEditorSerialTimeout); + addField(fEditorNetworkTimeout); + } + protected void setupListeners() { + TerminalSelectionHandler selectionHandler; + Button ctlButton; + + selectionHandler = new TerminalSelectionHandler(); + ctlButton = fEditorLimitOutput.getChangeControl(getFieldEditorParent()); + ctlButton.addSelectionListener(selectionHandler); + } + public class TerminalBooleanFieldEditor extends BooleanFieldEditor { + public TerminalBooleanFieldEditor(String strName, String strLabel, + Composite ctlParent) { + super(strName, strLabel, ctlParent); + } + public Button getChangeControl(Composite parent) { + return super.getChangeControl(parent); + } + } + protected class TerminalSelectionHandler extends SelectionAdapter { + protected TerminalSelectionHandler() { + super(); + } + public void widgetSelected(SelectionEvent event) { + Object source; + Button ctlButton; + + source = event.getSource(); + ctlButton = fEditorLimitOutput + .getChangeControl(getFieldEditorParent()); + + if (source == ctlButton) { + onLimitOutputSelected(); + } + } + + } +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalSettingsDlg.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalSettingsDlg.java new file mode 100644 index 00000000000..608c0c7cce7 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalSettingsDlg.java @@ -0,0 +1,143 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.terminal.ISettingsPage; +import org.eclipse.tm.terminal.ITerminalConnector; + +class TerminalSettingsDlg extends Dialog { + private Combo fCtlConnTypeCombo; + private final ITerminalConnector[] fConnectors; + private final ISettingsPage[] fPages; + private int fSelectedConnector; + private PageBook fPageBook; + + public TerminalSettingsDlg(Shell shell, ITerminalConnector[] connectors, ITerminalConnector connector) { + super(shell); + fConnectors=connectors; + fPages=new ISettingsPage[fConnectors.length]; + for (int i = 0; i < fConnectors.length; i++) { + fPages[i]=fConnectors[i].makeSettingsPage(); + if(fConnectors[i]==connector) + fSelectedConnector=i; + } + } + protected void okPressed() { + if (!validateSettings()) + return; + if(fSelectedConnector>=0) { + fPages[fSelectedConnector].saveSettings(); + } + super.okPressed(); + } + protected void cancelPressed() { + fSelectedConnector=-1; + super.cancelPressed(); + } + public int open() { + setShellStyle(getShellStyle() | SWT.RESIZE); + return super.open(); + } + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + + newShell.setText(ViewMessages.TERMINALSETTINGS); + } + protected Control createDialogArea(Composite parent) { + Composite ctlComposite = (Composite) super.createDialogArea(parent); + setupPanel(ctlComposite); + setupListeners(); + initFields(); + + return ctlComposite; + } + private void initFields() { + // Load controls + for (int i = 0; i < fPages.length; i++) { + String name=fPages[i].getName(); + fCtlConnTypeCombo.add(name); + if(fSelectedConnector==i) { + fCtlConnTypeCombo.select(i); + selectPage(i); + } + } + } + private boolean validateSettings() { + if(fSelectedConnector<0) + return true; + return fPages[fSelectedConnector].validateSettings(); + } + private void setupPanel(Composite wndParent) { + setupConnTypePanel(wndParent); + setupSettingsGroup(wndParent); + } + private void setupConnTypePanel(Composite wndParent) { + Group wndGroup; + GridLayout gridLayout; + GridData gridData; + + wndGroup = new Group(wndParent, SWT.NONE); + gridLayout = new GridLayout(1, true); + gridData = new GridData(GridData.FILL_HORIZONTAL); + + wndGroup.setLayout(gridLayout); + wndGroup.setLayoutData(gridData); + wndGroup.setText(ViewMessages.CONNECTIONTYPE + ":"); //$NON-NLS-1$ + + fCtlConnTypeCombo = new Combo(wndGroup, SWT.DROP_DOWN | SWT.READ_ONLY); + gridData = new GridData(GridData.FILL_HORIZONTAL); + gridData.widthHint = 200; + fCtlConnTypeCombo.setLayoutData(gridData); + } + private void setupSettingsGroup(Composite parent) { + Group group = new Group(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(); + GridData gridData = new GridData(GridData.FILL_BOTH); + + group.setText(ViewMessages.SETTINGS + ":"); //$NON-NLS-1$ + group.setLayout(gridLayout); + group.setLayoutData(gridData); + fPageBook=new PageBook(group,SWT.NONE); + for (int i = 0; i < fPages.length; i++) { + fPages[i].createControl(fPageBook); + } + } + private void setupListeners() { + fCtlConnTypeCombo.addSelectionListener(new SelectionAdapter() { + public void widgetSelected(SelectionEvent event) { + selectPage(fCtlConnTypeCombo.getSelectionIndex()); + } + }); + } + public ITerminalConnector getConnector() { + if(fSelectedConnector>=0) + return fConnectors[fSelectedConnector]; + return null; + } + private void selectPage(int index) { + fSelectedConnector=index; + Control[] pages=fPageBook.getChildren(); + fPageBook.showPage(pages[fSelectedConnector]); + } +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalView.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalView.java new file mode 100644 index 00000000000..38cfea804a0 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalView.java @@ -0,0 +1,657 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IMenuListener; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.resource.FontRegistry; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.events.MenuEvent; +import org.eclipse.swt.events.MenuListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.tm.terminal.ISettingsStore; +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalConnectorExtension; +import org.eclipse.tm.terminal.TerminalState; +import org.eclipse.tm.terminal.internal.actions.TerminalAction; +import org.eclipse.tm.terminal.internal.actions.TerminalActionClearAll; +import org.eclipse.tm.terminal.internal.actions.TerminalActionConnect; +import org.eclipse.tm.terminal.internal.actions.TerminalActionCopy; +import org.eclipse.tm.terminal.internal.actions.TerminalActionCut; +import org.eclipse.tm.terminal.internal.actions.TerminalActionDisconnect; +import org.eclipse.tm.terminal.internal.actions.TerminalActionNewTerminal; +import org.eclipse.tm.terminal.internal.actions.TerminalActionPaste; +import org.eclipse.tm.terminal.internal.actions.TerminalActionSelectAll; +import org.eclipse.tm.terminal.internal.actions.TerminalActionSettings; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchActionConstants; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.actions.ActionFactory; +import org.eclipse.ui.actions.RetargetAction; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.internal.WorkbenchWindow; +import org.eclipse.ui.part.ViewPart; +import org.eclipse.tm.terminal.control.ITerminalListener; +import org.eclipse.tm.terminal.control.ITerminalViewControl; +import org.eclipse.tm.terminal.control.TerminalViewControlFactory; + +public class TerminalView extends ViewPart implements ITerminalView, ITerminalListener { + public static final String FONT_DEFINITION = "terminal.views.view.font.definition"; //$NON-NLS-1$ + protected static final String fSecondaryTerminalCountMutex = ""; //$NON-NLS-1$ + + protected static int fSecondaryTerminalCount = 0; + + protected ITerminalViewControl fCtlTerminal; + + protected TerminalAction fActionTerminalNewTerminal; + + protected TerminalAction fActionTerminalConnect; + + protected TerminalAction fActionTerminalDisconnect; + + protected TerminalAction fActionTerminalSettings; + + protected TerminalAction fActionEditCopy; + + protected TerminalAction fActionEditCut; + + protected TerminalAction fActionEditPaste; + + protected TerminalAction fActionEditClearAll; + + protected TerminalAction fActionEditSelectAll; + + protected TerminalMenuHandlerEdit fMenuHandlerEdit; + + protected TerminalPropertyChangeHandler fPropertyChangeHandler; + + protected boolean fMenuAboutToShow; + + private ISettingsStore fStore; + + /** Remember the item with which we contributed the shortcut to unregister them again! */ + private IContextActivation fRememberedContextActivation; + + public TerminalView() { + Logger + .log("==============================================================="); //$NON-NLS-1$ + } + + private void XXXXX() { + Preferences preferences = TerminalViewPlugin.getDefault().getPluginPreferences(); + boolean bLimitOutput = preferences.getBoolean(TerminalPreferencePage.PREF_LIMITOUTPUT); + int bufferLineLimit = preferences.getInt(TerminalPreferencePage.PREF_BUFFERLINES); + + } + // TerminalTarget interface + public void setState(final TerminalState state) { + Runnable runnable=new Runnable() { + public void run() { + updateStatus(); + onTerminalStatus(); + } + }; + if(Thread.currentThread()==Display.getDefault().getThread()) + runnable.run(); + else + Display.getDefault().syncExec(runnable); + } + + + /** + * Display a new Terminal view. This method is called when the user clicks the New + * Terminal button in any Terminal view's toolbar. + */ + public void onTerminalNewTerminal() { + Logger.log("creating new Terminal instance."); //$NON-NLS-1$ + + try { + // The second argument to showView() is a unique String identifying the + // secondary view instance. If it ever matches a previously used secondary + // view identifier, then this call will not create a new Terminal view, + // which is undesireable. Therefore, we append the current time in + // milliseconds to the secondary view identifier to ensure it is always + // unique. This code runs only when the user clicks the New Terminal + // button, so there is no risk that this code will run twice in a single + // millisecond. + + getSite().getPage().showView( + "org.eclipse.tm.terminal.view.TerminalView",//$NON-NLS-1$ + "SecondaryTerminal" + System.currentTimeMillis(), //$NON-NLS-1$ + IWorkbenchPage.VIEW_ACTIVATE); + } catch (PartInitException ex) { + Logger.logException(ex); + } + } + + public void onTerminalConnect() { + if (isConnected()) + return; + if(fCtlTerminal.getTerminalConnection()==null) + setConnector(showSettingsDialog()); + fCtlTerminal.connectTerminal(); + } + + public void updateStatus() { + updateTerminalConnect(); + updateTerminalDisconnect(); + updateTerminalSettings(); + } + + public void updateTerminalConnect() { + boolean bEnabled = ((!isConnecting()) && (!fCtlTerminal.isConnected())); + + fActionTerminalConnect.setEnabled(bEnabled); + } + + private boolean isConnecting() { + return fCtlTerminal.getState()==TerminalState.CONNECTING; + } + private boolean isConnected() { + return fCtlTerminal.getState()==TerminalState.CONNECTED; + } + public void onTerminalDisconnect() { + fCtlTerminal.disconnectTerminal(); + } + + public void updateTerminalDisconnect() { + boolean bEnabled = ((isConnecting()) || (fCtlTerminal.isConnected())); + fActionTerminalDisconnect.setEnabled(bEnabled); + } + + public void onTerminalSettings() { + setConnector(showSettingsDialog()); + + onTerminalConnect(); + } + + private ITerminalConnector showSettingsDialog() { + // When the settings dialog is opened, load the Terminal settings from the + // persistent settings. + + TerminalSettingsDlg dlgTerminalSettings = new TerminalSettingsDlg(getViewSite().getShell(),fCtlTerminal.getConnectors(),fCtlTerminal.getTerminalConnection()); + + Logger.log("opening Settings dialog."); //$NON-NLS-1$ + + if (dlgTerminalSettings.open() == Window.CANCEL) { + Logger.log("Settings dialog cancelled."); //$NON-NLS-1$ + return null; + } + + Logger.log("Settings dialog OK'ed."); //$NON-NLS-1$ + + // When the settings dialog is closed, we persist the Terminal settings. + + saveSettings(); + return dlgTerminalSettings.getConnector(); + } + + private void setConnector(ITerminalConnector connector) { + fCtlTerminal.setConnector(connector); + } + + public void updateTerminalSettings() { + boolean bEnabled; + + bEnabled = ((!isConnecting()) && (!fCtlTerminal + .isConnected())); + + fActionTerminalSettings.setEnabled(bEnabled); + } + + public void setTerminalTitle(String strTitle) { + if (fCtlTerminal.isDisposed()) + return; + + if (strTitle != null) { + // When parameter 'data' is not null, it is a String containing text to + // display in the view's content description line. This is used by class + // TerminalText when it processes an ANSI OSC escape sequence that commands + // the terminal to display text in its title bar. + } else { + // When parameter 'data' is null, we construct a descriptive string to + // display in the content description line. + String strConnected = getStateDisplayName(fCtlTerminal.getState()); + String status=""; //$NON-NLS-1$ + status=fCtlTerminal.getStatusString(strConnected); + strTitle = ViewMessages.PROP_TITLE + status; + } + + setContentDescription(strTitle); + getViewSite().getActionBars().getStatusLineManager().setMessage( + strTitle); + } + public void onTerminalStatus() { + setTerminalTitle(null); + } + + private String getStateDisplayName(TerminalState state) { + if(state==TerminalState.CONNECTED) { + return ViewMessages.STATE_CONNECTED; + } else if(state==TerminalState.CONNECTING) { + return ViewMessages.STATE_CONNECTING; + } else if(state==TerminalState.OPENED) { + return ViewMessages.STATE_OPENED; + } else if(state==TerminalState.CLOSED) { + return ViewMessages.STATE_CLOSED; + } else { + throw new IllegalStateException(state.toString()); + } + } + + public void onTerminalFontChanged() { + fCtlTerminal.getCtlText().setFont(JFaceResources.getFont(FONT_DEFINITION)); + + // Tell the TerminalControl singleton that the font has changed. + + fCtlTerminal.onFontChanged(); + } + + public void onEditCopy() { + String selection=fCtlTerminal.getSelection(); + + if (!selection.equals("")) {//$NON-NLS-1$ + fCtlTerminal.copy(); + } else { + fCtlTerminal.sendKey('\u0003'); + } + } + + public void updateEditCopy() { + boolean bEnabled=true; + + if (fMenuAboutToShow) { + bEnabled = fCtlTerminal.getSelection().length()>0; + } + + fActionEditCopy.setEnabled(bEnabled); + } + + public void onEditCut() { + fCtlTerminal.sendKey('\u0018'); + } + + public void updateEditCut() { + boolean bEnabled; + + bEnabled = !fMenuAboutToShow; + fActionEditCut.setEnabled(bEnabled); + } + + public void onEditPaste() { + fCtlTerminal.paste(); + } + + public void updateEditPaste() { + String strText = (String) fCtlTerminal.getClipboard().getContents(TextTransfer.getInstance()); + + boolean bEnabled = ((strText != null) && (!strText.equals("")) && (isConnected()));//$NON-NLS-1$ + + fActionEditPaste.setEnabled(bEnabled); + } + + public void onEditClearAll() { + fCtlTerminal.clearTerminal(); + } + + public void updateEditClearAll() { + fActionEditClearAll.setEnabled(!fCtlTerminal.isEmpty()); + } + + public void onEditSelectAll() { + fCtlTerminal.selectAll(); + } + + public void updateEditSelectAll() { + fActionEditSelectAll.setEnabled(!fCtlTerminal.isEmpty()); + } + + // ViewPart interface + + public void createPartControl(Composite wndParent) { + // Bind plugin.xml key bindings to this plugin. Overrides global Control-W key + // sequence. + + /** Activate the sy context allowing shortcuts like F3(open declaration) in the view */ + IContextService ctxtService = (IContextService) getSite().getService(IContextService.class); + fRememberedContextActivation = ctxtService.activateContext("org.eclipse.tm.terminal.TerminalPreferencePage"); //$NON-NLS-1$ + + synchronized (fSecondaryTerminalCountMutex) { + setPartName(ViewMessages.PROP_TITLE + " " + fSecondaryTerminalCount++); //$NON-NLS-1$ + } + + setupControls(wndParent); + setupActions(); + setupMenus(); + setupLocalToolBars(); + setupContextMenus(); + setupListeners(wndParent); + + onTerminalStatus(); + } + + public void dispose() { + Logger.log("entered."); //$NON-NLS-1$ + + setPartName("Terminal"); //$NON-NLS-1$ + + TerminalViewPlugin plugin; + IWorkbench workbench; + WorkbenchWindow workbenchWindow; + MenuManager menuMgr; + Menu menu; + + /** The context (for short cuts) was set above, now unset it again */ + if (fRememberedContextActivation != null) { + IContextService ctxService = (IContextService) getSite() + .getService(IContextService.class); + ctxService.deactivateContext(fRememberedContextActivation); + fRememberedContextActivation = null; + } + + JFaceResources.getFontRegistry().removeListener(fPropertyChangeHandler); + plugin = TerminalViewPlugin.getDefault(); + workbench = plugin.getWorkbench(); + workbenchWindow = (WorkbenchWindow) workbench + .getActiveWorkbenchWindow(); + menuMgr = workbenchWindow.getMenuManager(); + menuMgr = (MenuManager) menuMgr + .findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + menu = menuMgr.getMenu(); + + menuMgr.removeMenuListener(fMenuHandlerEdit); + + if (menu != null) + menu.removeMenuListener(fMenuHandlerEdit); + + fCtlTerminal.disposeTerminal(); + } + + /** + * Passing the focus request to the viewer's control. + */ + public void setFocus() { + fCtlTerminal.setFocus(); + } + + /** + * This method creates the top-level control for the Terminal view. + */ + protected void setupControls(Composite wndParent) { + ITerminalConnector[] connectors=TerminalConnectorExtension.getTerminalConnectors(); + fCtlTerminal = TerminalViewControlFactory.makeControl(this, wndParent, connectors); + String connectionType=getStore().get("ConnectionType"); //$NON-NLS-1$ + for (int i = 0; i < connectors.length; i++) { + connectors[i].load(getStore(connectors[i])); + if(connectors[i].getId().equals(connectionType)) + fCtlTerminal.setConnector(connectors[i]); + } + } + private void saveSettings() { + ITerminalConnector[] connectors=fCtlTerminal.getConnectors(); + for (int i = 0; i < connectors.length; i++) { + connectors[i].save(getStore(connectors[i])); + } + if(fCtlTerminal.getTerminalConnection()!=null) { + getStore().put("ConnectionType",fCtlTerminal.getTerminalConnection().getId()); //$NON-NLS-1$ + } + } + + private ISettingsStore getStore() { + if(fStore==null) + fStore=new SettingsStore(getPartName()); + return fStore; + } + + private ISettingsStore getStore(ITerminalConnector connector) { + return new SettingStorePrefixDecorator(getStore(),connector.getClass().getName()+"."); //$NON-NLS-1$ + } + + protected void setupActions() { + fActionTerminalNewTerminal = new TerminalActionNewTerminal(this); + fActionTerminalConnect = new TerminalActionConnect(this); + fActionTerminalDisconnect = new TerminalActionDisconnect(this); + fActionTerminalSettings = new TerminalActionSettings(this); + fActionEditCopy = new TerminalActionCopy(this); + fActionEditCut = new TerminalActionCut(this); + fActionEditPaste = new TerminalActionPaste(this); + fActionEditClearAll = new TerminalActionClearAll(this); + fActionEditSelectAll = new TerminalActionSelectAll(this); + + IActionBars actionBars = getViewSite().getActionBars(); + actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), fActionEditCopy); + + actionBars.setGlobalActionHandler(ActionFactory.CUT.getId(), fActionEditCut); + + actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), fActionEditPaste); + + actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), fActionEditSelectAll); + } + + protected void setupMenus() { + TerminalViewPlugin plugin; + IWorkbench workbench; + WorkbenchWindow workbenchWindow; + MenuManager menuMgr; + Menu menu; + + fMenuHandlerEdit = new TerminalMenuHandlerEdit(); + plugin = TerminalViewPlugin.getDefault(); + workbench = plugin.getWorkbench(); + workbenchWindow = (WorkbenchWindow) workbench + .getActiveWorkbenchWindow(); + menuMgr = workbenchWindow.getMenuManager(); + menuMgr = (MenuManager) menuMgr + .findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + menu = menuMgr.getMenu(); + + menuMgr.addMenuListener(fMenuHandlerEdit); + menu.addMenuListener(fMenuHandlerEdit); + } + + protected void setupLocalToolBars() { + IToolBarManager toolBarMgr = getViewSite().getActionBars().getToolBarManager(); + + toolBarMgr.add(fActionTerminalNewTerminal); + toolBarMgr.add(fActionTerminalConnect); + toolBarMgr.add(fActionTerminalDisconnect); + toolBarMgr.add(fActionTerminalSettings); + } + + protected void setupContextMenus() { + StyledText ctlText; + MenuManager menuMgr; + Menu menu; + TerminalContextMenuHandler contextMenuHandler; + + ctlText = fCtlTerminal.getCtlText(); + menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ + menu = menuMgr.createContextMenu(ctlText); + contextMenuHandler = new TerminalContextMenuHandler(); + + ctlText.setMenu(menu); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(contextMenuHandler); + menu.addMenuListener(contextMenuHandler); + } + + protected void loadContextMenus(IMenuManager menuMgr) { + menuMgr.add(fActionEditCopy); + menuMgr.add(fActionEditPaste); + menuMgr.add(new Separator()); + menuMgr.add(fActionEditClearAll); + menuMgr.add(fActionEditSelectAll); + + // Other plug-ins can contribute there actions here + menuMgr.add(new Separator("Additions")); //$NON-NLS-1$ + } + + protected void setupListeners(Composite wndParent) { + fPropertyChangeHandler = new TerminalPropertyChangeHandler(); + JFaceResources.getFontRegistry().addListener(fPropertyChangeHandler); + } + + // Inner classes + + protected class TerminalMenuHandlerEdit implements MenuListener, IMenuListener { + protected String fActionDefinitionIdCopy; + + protected String fActionDefinitionIdPaste; + + protected String fActionDefinitionIdSelectAll; + + protected int fAcceleratorCopy; + + protected int fAcceleratorPaste; + + protected int fAcceleratorSelectAll; + + protected TerminalMenuHandlerEdit() { + super(); + + fActionDefinitionIdCopy = ""; //$NON-NLS-1$ + fActionDefinitionIdPaste = ""; //$NON-NLS-1$ + fActionDefinitionIdSelectAll = ""; //$NON-NLS-1$ + + fAcceleratorCopy = 0; + fAcceleratorPaste = 0; + fAcceleratorSelectAll = 0; + } + public void menuAboutToShow(IMenuManager menuMgr) { + + fMenuAboutToShow = true; + updateEditCopy(); + updateEditCut(); + updateEditPaste(); + updateEditSelectAll(); + + ActionContributionItem item = (ActionContributionItem) menuMgr.find(ActionFactory.COPY.getId()); + RetargetAction action = (RetargetAction) item.getAction(); + fActionDefinitionIdCopy = action.getActionDefinitionId(); + fAcceleratorCopy = action.getAccelerator(); + action.setActionDefinitionId(null); + action.enableAccelerator(false); + item.update(); + + item = (ActionContributionItem) menuMgr.find(ActionFactory.PASTE.getId()); + action = (RetargetAction) item.getAction(); + fActionDefinitionIdPaste = action.getActionDefinitionId(); + fAcceleratorPaste = action.getAccelerator(); + action.setActionDefinitionId(null); + action.enableAccelerator(false); + item.update(); + + item = (ActionContributionItem) menuMgr.find(ActionFactory.SELECT_ALL.getId()); + action = (RetargetAction) item.getAction(); + fActionDefinitionIdSelectAll = action.getActionDefinitionId(); + fAcceleratorSelectAll = action.getAccelerator(); + action.setActionDefinitionId(null); + action.enableAccelerator(false); + item.update(); + } + public void menuShown(MenuEvent event) { + // do nothing + } + public void menuHidden(MenuEvent event) { + TerminalViewPlugin plugin; + IWorkbench workbench; + WorkbenchWindow workbenchWindow; + MenuManager menuMgr; + ActionContributionItem item; + RetargetAction action; + + fMenuAboutToShow = false; + updateEditCopy(); + updateEditCut(); + + plugin = TerminalViewPlugin.getDefault(); + workbench = plugin.getWorkbench(); + workbenchWindow = (WorkbenchWindow) workbench + .getActiveWorkbenchWindow(); + menuMgr = workbenchWindow.getMenuManager(); + menuMgr = (MenuManager) menuMgr + .findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); + + item = (ActionContributionItem) menuMgr.find(ActionFactory.COPY + .getId()); + action = (RetargetAction) item.getAction(); + action.setActionDefinitionId(fActionDefinitionIdCopy); + action.setAccelerator(fAcceleratorCopy); + action.enableAccelerator(true); + item.update(); + + item = (ActionContributionItem) menuMgr.find(ActionFactory.PASTE + .getId()); + action = (RetargetAction) item.getAction(); + action.setActionDefinitionId(fActionDefinitionIdPaste); + action.setAccelerator(fAcceleratorPaste); + action.enableAccelerator(true); + item.update(); + + item = (ActionContributionItem) menuMgr + .find(ActionFactory.SELECT_ALL.getId()); + action = (RetargetAction) item.getAction(); + action.setActionDefinitionId(fActionDefinitionIdSelectAll); + action.setAccelerator(fAcceleratorSelectAll); + action.enableAccelerator(true); + item.update(); + } + } + + protected class TerminalContextMenuHandler implements MenuListener, IMenuListener { + public void menuHidden(MenuEvent event) { + fMenuAboutToShow = false; + updateEditCopy(); + } + + public void menuShown(MenuEvent e) { + // + } + public void menuAboutToShow(IMenuManager menuMgr) { + fMenuAboutToShow = true; + updateEditCopy(); + updateEditCut(); + updateEditPaste(); + updateEditClearAll(); + + loadContextMenus(menuMgr); + } + } + + protected class TerminalPropertyChangeHandler implements IPropertyChangeListener { + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(FONT_DEFINITION)) { + onTerminalFontChanged(); + } + } + } +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalViewPlugin.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalViewPlugin.java new file mode 100644 index 00000000000..2a300c72ca6 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/TerminalViewPlugin.java @@ -0,0 +1,140 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.view; + +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Iterator; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +public class TerminalViewPlugin extends AbstractUIPlugin { + protected static TerminalViewPlugin fDefault; + public static final String PLUGIN_HOME = "org.eclipse.tm.terminal"; //$NON-NLS-1$ + public static final String HELP_VIEW = PLUGIN_HOME + ".terminal_view"; //$NON-NLS-1$ + + /** + * The constructor. + */ + public TerminalViewPlugin() { + fDefault = this; + } + protected void initializeImageRegistry(ImageRegistry imageRegistry) { + HashMap map; + + map = new HashMap(); + + try { + // Local toolbars + map.put(ImageConsts.IMAGE_NEW_TERMINAL, "newterminal.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_CLCL_CONNECT, "connect_co.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_CLCL_DISCONNECT, "disconnect_co.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_CLCL_SETTINGS, "properties_tsk.gif"); //$NON-NLS-1$ + + loadImageRegistry(imageRegistry, ImageConsts.IMAGE_DIR_LOCALTOOL, map); + + map.clear(); + + // Enabled local toolbars + map.put(ImageConsts.IMAGE_NEW_TERMINAL, "newterminal.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_ELCL_CONNECT, "connect_co.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_ELCL_DISCONNECT, "disconnect_co.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_ELCL_SETTINGS, "properties_tsk.gif"); //$NON-NLS-1$ + + loadImageRegistry(imageRegistry, ImageConsts.IMAGE_DIR_ELCL, map); + + map.clear(); + + // Disabled local toolbars + map.put(ImageConsts.IMAGE_NEW_TERMINAL, "newterminal.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_DLCL_CONNECT, "connect_co.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_DLCL_DISCONNECT, "disconnect_co.gif"); //$NON-NLS-1$ + map.put(ImageConsts.IMAGE_DLCL_SETTINGS, "properties_tsk.gif"); //$NON-NLS-1$ + + loadImageRegistry(imageRegistry, ImageConsts.IMAGE_DIR_DLCL, map); + + map.clear(); + } catch (MalformedURLException malformedURLException) { + malformedURLException.printStackTrace(); + } + } + protected void initializeDefaultPreferences(IPreferenceStore store) { + store.setDefault(TerminalPreferencePage.PREF_LIMITOUTPUT, + TerminalPreferencePage.DEFAULT_LIMITOUTPUT); + store.setDefault(TerminalPreferencePage.PREF_BUFFERLINES, + TerminalPreferencePage.DEFAULT_BUFFERLINES); + store.setDefault(TerminalPreferencePage.PREF_TIMEOUT_SERIAL, + TerminalPreferencePage.DEFAULT_TIMEOUT_SERIAL); + store.setDefault(TerminalPreferencePage.PREF_TIMEOUT_NETWORK, + TerminalPreferencePage.DEFAULT_TIMEOUT_NETWORK); + } + /** + * Returns the shared instance. + */ + public static TerminalViewPlugin getDefault() { + return fDefault; + } + + public static boolean isLogInfoEnabled() { + return isOptionEnabled(Logger.TRACE_DEBUG_LOG_INFO); + } + public static boolean isLogErrorEnabled() { + return isOptionEnabled(Logger.TRACE_DEBUG_LOG_ERROR); + } + public static boolean isLogEnabled() { + return isOptionEnabled(Logger.TRACE_DEBUG_LOG); + } + + public static boolean isOptionEnabled(String strOption) { + String strEnabled; + Boolean boolEnabled; + boolean bEnabled; + + strEnabled = Platform.getDebugOption(strOption); + if (strEnabled == null) + return false; + + boolEnabled = new Boolean(strEnabled); + bEnabled = boolEnabled.booleanValue(); + + return bEnabled; + } + protected void loadImageRegistry(ImageRegistry imageRegistry, + String strDir, HashMap map) throws MalformedURLException { + URL url; + ImageDescriptor imageDescriptor; + Iterator keys; + String strKey; + String strFile; + + keys = map.keySet().iterator(); + + while (keys.hasNext()) { + strKey = (String) keys.next(); + strFile = (String) map.get(strKey); + + if (strFile != null) { + url = TerminalViewPlugin.getDefault().getBundle().getEntry( + ImageConsts.IMAGE_DIR_ROOT + strDir + strFile); + imageDescriptor = ImageDescriptor.createFromURL(url); + imageRegistry.put(strKey, imageDescriptor); + } + } + } +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.java new file mode 100644 index 00000000000..425c31539d6 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.view; + +import org.eclipse.osgi.util.NLS; +public class ViewMessages extends NLS { + static { + NLS.initializeMessages(ViewMessages.class.getName(), ViewMessages.class); + } + public static String PROP_TITLE; + public static String SETTINGS; + + public static String TERMINALSETTINGS; + public static String CONNECTIONTYPE; + + public static String LIMITOUTPUT; + public static String BUFFERLINES; + public static String SERIALTIMEOUT; + public static String NETWORKTIMEOUT; + + public static String STATE_CONNECTED; + public static String STATE_CONNECTING; + public static String STATE_OPENED; + public static String STATE_CLOSED; + +} diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.properties b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.properties new file mode 100644 index 00000000000..5d9d0c549ed --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/internal/view/ViewMessages.properties @@ -0,0 +1,27 @@ +############################################################################### +# Copyright (c) 2006 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: +# Wind River Systems, Inc. - initial implementation +# +############################################################################### +PROP_TITLE = Terminal +SETTINGS = Settings + + +TERMINALSETTINGS = Terminal Settings +CONNECTIONTYPE = Connection Type + +LIMITOUTPUT = Limit terminal output +BUFFERLINES = Terminal buffer lines: +SERIALTIMEOUT = Serial timeout (seconds): +NETWORKTIMEOUT = Network timeout (seconds): + +STATE_CONNECTED = CONNECTED +STATE_CONNECTING = CONNECTING... +STATE_OPENED = OPENED +STATE_CLOSED = CLOSED diff --git a/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/view/Activator.java b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/view/Activator.java new file mode 100644 index 00000000000..f93c2d7e379 --- /dev/null +++ b/org.eclipse.tm.terminal.view/src/org/eclipse/tm/terminal/view/Activator.java @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.view; + +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends AbstractUIPlugin { + + // The plug-in ID + public static final String PLUGIN_ID = "org.eclipse.tm.terminal.internal.view"; + + // The shared instance + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + plugin = this; + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext context) throws Exception { + super.start(context); + } + + /* + * (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + +} diff --git a/org.eclipse.tm.terminal/.classpath b/org.eclipse.tm.terminal/.classpath index 899ab4bb39a..52165ecfb58 100644 --- a/org.eclipse.tm.terminal/.classpath +++ b/org.eclipse.tm.terminal/.classpath @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.tm.terminal/.project b/org.eclipse.tm.terminal/.project index 621a3a690cf..fa6a642ade2 100644 --- a/org.eclipse.tm.terminal/.project +++ b/org.eclipse.tm.terminal/.project @@ -20,9 +20,15 @@ + + net.sourceforge.metrics.builder + + + org.eclipse.pde.PluginNature org.eclipse.jdt.core.javanature + net.sourceforge.metrics.nature diff --git a/org.eclipse.tm.terminal/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.tm.terminal/.settings/org.eclipse.jdt.core.prefs index 175992f9e31..78cc64039c4 100644 --- a/org.eclipse.tm.terminal/.settings/org.eclipse.jdt.core.prefs +++ b/org.eclipse.tm.terminal/.settings/org.eclipse.jdt.core.prefs @@ -1,8 +1,58 @@ -#Mon Jul 31 14:55:18 CEST 2006 +#Thu Nov 30 18:38:38 CET 2006 eclipse.preferences.version=1 org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=disabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.4 org.eclipse.jdt.core.compiler.compliance=1.4 +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=ignore +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning +org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore +org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore +org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning +org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning +org.eclipse.jdt.core.compiler.problem.forbiddenReference=error +org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning +org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning +org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=warning +org.eclipse.jdt.core.compiler.problem.nullReference=ignore +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled +org.eclipse.jdt.core.compiler.problem.unusedImport=warning +org.eclipse.jdt.core.compiler.problem.unusedLabel=warning +org.eclipse.jdt.core.compiler.problem.unusedLocal=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled +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.4 diff --git a/org.eclipse.tm.terminal/META-INF/MANIFEST.MF b/org.eclipse.tm.terminal/META-INF/MANIFEST.MF index 3e3cd8e261f..2cdddadf319 100644 --- a/org.eclipse.tm.terminal/META-INF/MANIFEST.MF +++ b/org.eclipse.tm.terminal/META-INF/MANIFEST.MF @@ -2,17 +2,15 @@ Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: %pluginName Bundle-SymbolicName: org.eclipse.tm.terminal; singleton:=true -Bundle-Version: 2.6.0 -Bundle-Activator: org.eclipse.tm.terminal.TerminalPlugin +Bundle-Version: 2.7.0 +Bundle-Activator: org.eclipse.tm.terminal.internal.control.TerminalPlugin Bundle-Vendor: %providerName Bundle-Localization: plugin Require-Bundle: org.eclipse.core.runtime, - org.eclipse.ui.ide, - org.eclipse.ui.views, - org.eclipse.ui.workbench.texteditor, - org.eclipse.ui.editors, - org.eclipse.core.resources, org.eclipse.ui, org.eclipse.jface.text Eclipse-LazyStart: true Bundle-RequiredExecutionEnvironment: J2SE-1.4 +Bundle-ClassPath: . +Export-Package: org.eclipse.tm.terminal, + org.eclipse.tm.terminal.control diff --git a/org.eclipse.tm.terminal/README.txt b/org.eclipse.tm.terminal/README.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/org.eclipse.tm.terminal/build.properties b/org.eclipse.tm.terminal/build.properties new file mode 100644 index 00000000000..6ade83c7191 --- /dev/null +++ b/org.eclipse.tm.terminal/build.properties @@ -0,0 +1,14 @@ +bin.includes = .,\ + src/,\ + META-INF/,\ + plugin.xml,\ + .classpath,\ + .project,\ + build.properties,\ + plugin.properties,\ + schema/,\ + .settings/ + +source.. = src/ +output.. = bin/ + \ No newline at end of file diff --git a/org.eclipse.tm.terminal/plugin.properties b/org.eclipse.tm.terminal/plugin.properties index e4f0b2c67f0..9729533eb89 100644 --- a/org.eclipse.tm.terminal/plugin.properties +++ b/org.eclipse.tm.terminal/plugin.properties @@ -4,14 +4,3 @@ pluginName = Terminal providerName = Eclipse.org -terminal.views.category.name = Device Debug -terminal.views.view.name = Terminal -terminal.views.view.font.description = The font for the terminal console. -terminal.views.view.font.label = Terminal Console Font - -terminal.view.context.name=Terminal view context -terminal.view.context.description=control-q override - -terminal.view.insertion.description=Terminal view insertion -terminal.view.insertion.name=Terminal view insert -terminal.view.insertion.category.name=Terminal view commands diff --git a/org.eclipse.tm.terminal/plugin.xml b/org.eclipse.tm.terminal/plugin.xml index 28229ed8aa1..7223dede489 100644 --- a/org.eclipse.tm.terminal/plugin.xml +++ b/org.eclipse.tm.terminal/plugin.xml @@ -1,128 +1,9 @@ + - - - - + point="org.eclipse.tm.terminal.terminalConnector"> + - - - - - - - - - - - - - - - - %terminal.views.view.font.description - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/org.eclipse.tm.terminal/schema/terminalConnector.exsd b/org.eclipse.tm.terminal/schema/terminalConnector.exsd new file mode 100644 index 00000000000..c6848fc8623 --- /dev/null +++ b/org.eclipse.tm.terminal/schema/terminalConnector.exsd @@ -0,0 +1,105 @@ + + + + + + + + + [Enter description of this extension point.] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [Enter the first release in which this extension point appears.] + + + + + + + + + [Enter extension point usage example here.] + + + + + + + + + [Enter API information here.] + + + + + + + + + [Enter information about supplied implementation of this extension point.] + + + + + + + + + + + + + diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsPage.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsPage.java new file mode 100644 index 00000000000..7a7f751f98a --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsPage.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal; + +import org.eclipse.swt.widgets.Composite; + +/** + * @author Michael Scharf + * + * TODO: Michael Scharf: provide a mechanism to set an error string + * TODO: Michael Scharf: provide a long description of a wizard + * TODO: Michael Scharf: allow multiple pages to be generated + */ +public interface ISettingsPage { + /** + * Create a page to be shown in a dialog or wizard to setup the connection. + * @param parent + */ + void createControl(Composite parent); + /** + * Called before the page is shown. Loads the state from the {@link ITerminalConnector}. + */ + void loadSettings(); + /** + * Called when the OK button is pressed. + */ + void saveSettings(); + /** + * @return true if the + */ + boolean validateSettings(); + /** + * @return a name of the connection type. Used in a tab page title or drop + * down to select the connection. + */ + String getName(); + +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsStore.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsStore.java new file mode 100644 index 00000000000..ba6602be0a6 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ISettingsStore.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal; + +/** + * A simple interface to a store to persist the state of a connection. + * + * + *

Not to be implemented. + * @author Michael Scharf + * + */ +public interface ISettingsStore { + /** + * @param key + * @return value + */ + String get(String key); + /** + * @param key + * @param defaultValue + * @return the value or the fecaault + */ + String get(String key, String defaultValue); + /** + * Save a string value + * @param key + * @param value + */ + void put(String key, String value); +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalConnector.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalConnector.java new file mode 100644 index 00000000000..9dd88afb6fd --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalConnector.java @@ -0,0 +1,98 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal; + +import java.io.InputStream; +import java.io.OutputStream; + + +/** + * Manage a single connection. Implementations of this class are contributed + * via org.eclipse.tm.terminal.terminalConnector extension point. + * + * @author Michael Scharf + * + */ +public interface ITerminalConnector { + /** + * @return an ID of this connector. Typically getClass().getName() + */ + String getId(); + /** + * @return true if the contribution is functioning (e.g. all external libraries are + * installed). This was added for the serial support, because it requires the java comm + * library, which is installed in the lib/ext directory of the + */ + boolean isInstalled(); + /** + * Connect using the current state of the settings. + * @param control Used to inform the UI about state changes and messages from the connection. + */ + void connect(ITerminalControl control); + /** + * Disconnect if connected. Else do nothing. + */ + void disconnect(); + + /** + * @return true if a local echo is needed. + * TODO:Michael Scharf: this should be handed within the connection.... + */ + boolean isLocalEcho(); + + /** + * Notify the remote site that the size of the terminal has changed. + * @param newWidth + * @param newHeight + */ + void setTerminalSize(int newWidth, int newHeight); + + /** + * @return a stream with data coming from the remote site. + */ + OutputStream getOutputStream(); + /** + * @return a stream to write to the remote site. + */ + InputStream getInputStream(); + + /** + * Load the state of this connection. Is typically called before + * {@link #connect(ITerminalControl)}. + * + * @param store a string based data store. Short keys like "foo" can be used to + * store the state of the connectio. + */ + void load(ISettingsStore store); + + /** + * When the view or dialog containing the terminal is closed, + * the state of the connection is saved into the settings store store + * @param store + */ + void save(ISettingsStore store); + + /** + * @return a new page that can be used in a dialog to setup this connection. + * + */ + ISettingsPage makeSettingsPage(); + + /** + * @param connectedLabel a String with the connected state {@link TerminalState}. + * Like "CONNECTED", "CLOSED". Can be used to build up the status string. + * @return A string that represents the state of the connection. + * TODO: Michael Scharf: + */ + String getStatusString(String connectedLabel); + +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java new file mode 100644 index 00000000000..434008acc6e --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/ITerminalControl.java @@ -0,0 +1,65 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal; + +import org.eclipse.swt.widgets.Shell; + +/** + * Represents the terminal view as seen by a terminal connection. + * + *

Not to be implemented by clients. + * @author Michael Scharf + * + */ +public interface ITerminalControl { + + /** + * @return the current state of the connection + */ + TerminalState getState(); + /** + * @param state + */ + void setState(TerminalState state); + + /** + * A shell to show dialogs. + * @return the shell in which the terminal is shown. + * TODO: Michael Scharf: it's not clear to me what the meaning of the open state is + */ + Shell getShell(); + + /** + * Show a text in the terminal. If pots newlines at the beginning and the end. + * @param text + * TODO: Michael Scharf: Is this really needed? (use {@link #displayTextInTerminal(String)} + */ + void displayTextInTerminal(String text); + /** + * Write a string directly to the terminal. + * @param txt + */ + void writeToTerminal(String txt); + /** + * Set the title of the terminal view. + * @param title + */ + void setTerminalTitle(String title); + + /** + * Show an error message during connect. + * @param msg + * TODO: Michael Scharf: Should be replaced by a better error notification mechansim! + */ + void setMsg(String msg); + +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Logger.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Logger.java index 1c319e18fa1..7a2a0e061c6 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Logger.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Logger.java @@ -16,102 +16,98 @@ import java.io.File; import java.io.FileOutputStream; import java.io.PrintStream; - /** - * A simple logger class. Every method in this class is static, so they can be called - * from both class and instance methods. To use this class, write code like this:

- * + * A simple logger class. Every method in this class is static, so they can be + * called from both class and instance methods. To use this class, write code + * like this: + *

+ * *

- *      Logger.log("something has happened");
- *      Logger.log("counter is " + counter);
+ * Logger.log("something has happened");
+ * Logger.log("counter is " + counter);
  * 
- * + * * @author Fran Litterio */ -public final class Logger -{ - /** - * UNDER CONSTRUCTION - */ +public final class Logger { + public static final String TRACE_DEBUG_LOG = "org.eclipse.tm.terminal/debug/log"; //$NON-NLS-1$ + public static final String TRACE_DEBUG_LOG_ERROR = "org.eclipse.tm.terminal/debug/log/error"; //$NON-NLS-1$ + public static final String TRACE_DEBUG_LOG_INFO = "org.eclipse.tm.terminal/debug/log/info"; //$NON-NLS-1$ + public static final String TRACE_DEBUG_LOG_CHAR = "org.eclipse.tm.terminal/debug/log/char"; //$NON-NLS-1$ + public static final String TRACE_DEBUG_LOG_BUFFER_SIZE = "org.eclipse.tm.terminal/debug/log/buffer/size"; //$NON-NLS-1$ + private static PrintStream logStream; - static - { - String logFile = null; - File logDirWindows = new File("C:\\wblogs"); //$NON-NLS-1$ - File logDirUNIX = new File("/tmp/wblogs"); //$NON-NLS-1$ + static { + String logFile = null; + File logDirWindows = new File("C:\\wblogs"); //$NON-NLS-1$ + File logDirUNIX = new File("/tmp/wblogs"); //$NON-NLS-1$ - if (logDirWindows.isDirectory()) - { - logFile = logDirWindows + "\\wbterminal.log"; //$NON-NLS-1$ - } - else if (logDirUNIX.isDirectory()) - { - logFile = logDirUNIX + "/wbterminal.log"; //$NON-NLS-1$ - } + if (logDirWindows.isDirectory()) { + logFile = logDirWindows + "\\wbterminal.log"; //$NON-NLS-1$ + } else if (logDirUNIX.isDirectory()) { + logFile = logDirUNIX + "/wbterminal.log"; //$NON-NLS-1$ + } - if (logFile != null) - { - try - { - logStream = new PrintStream(new FileOutputStream(logFile, true)); - } - catch (Exception ex) - { - logStream = System.err; - logStream.println("Exception when opening log file -- logging to stderr!"); //$NON-NLS-1$ - ex.printStackTrace(logStream); - } - } - } + if (logFile != null) { + try { + logStream = new PrintStream(new FileOutputStream(logFile, true)); + } catch (Exception ex) { + logStream = System.err; + logStream + .println("Exception when opening log file -- logging to stderr!"); //$NON-NLS-1$ + ex.printStackTrace(logStream); + } + } + } - /** - * Logs the specified message. Do not append a newline to parameter - * message. This method does that for you. - * + /** + * Logs the specified message. Do not append a newline to parameter + * message. This method does that for you. + * * @param message A String containing the message to log. - */ - public static final void log(String message) - { - if (logStream != null) - { - // Read my own stack to get the class name, method name, and line number of - // where this method was called. + */ + public static final void log(String message) { + if (logStream != null) { + // Read my own stack to get the class name, method name, and line + // number of + // where this method was called. - StackTraceElement caller = new Throwable().getStackTrace()[1]; - int lineNumber = caller.getLineNumber(); - String className = caller.getClassName(); - String methodName = caller.getMethodName(); - className = className.substring(className.lastIndexOf('.') + 1); + StackTraceElement caller = new Throwable().getStackTrace()[1]; + int lineNumber = caller.getLineNumber(); + String className = caller.getClassName(); + String methodName = caller.getMethodName(); + className = className.substring(className.lastIndexOf('.') + 1); logStream.println(className + "." + methodName + ":" + lineNumber + ": " + message); //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ - logStream.flush(); - } - } + logStream.flush(); + } + } - /** - * Writes a stack trace for an exception to both Standard Error and to the log file. - */ - public static final void logException(Exception ex) - { - // Read my own stack to get the class name, method name, and line number of - // where this method was called. + /** + * Writes a stack trace for an exception to both Standard Error and to the + * log file. + */ + public static final void logException(Exception ex) { + // Read my own stack to get the class name, method name, and line number + // of + // where this method was called. - StackTraceElement caller = new Throwable().getStackTrace()[1]; - int lineNumber = caller.getLineNumber(); - String className = caller.getClassName(); - String methodName = caller.getMethodName(); - className = className.substring(className.lastIndexOf('.') + 1); + StackTraceElement caller = new Throwable().getStackTrace()[1]; + int lineNumber = caller.getLineNumber(); + String className = caller.getClassName(); + String methodName = caller.getMethodName(); + className = className.substring(className.lastIndexOf('.') + 1); - PrintStream tmpStream = System.err; + PrintStream tmpStream = System.err; - if (logStream != null) - { - tmpStream = logStream; - } + if (logStream != null) { + tmpStream = logStream; + } - tmpStream.println(className + "." + methodName + ":" + lineNumber + ": " + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ - "Caught exception: " + ex); //$NON-NLS-1$ - ex.printStackTrace(tmpStream); - } + tmpStream.println(className + + "." + methodName + ":" + lineNumber + ": " + //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ + "Caught exception: " + ex); //$NON-NLS-1$ + ex.printStackTrace(tmpStream); + } } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.java deleted file mode 100644 index 9defcc72685..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.java +++ /dev/null @@ -1,40 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -public class Messages -{ - private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.Messages"; //$NON-NLS-1$ - - private static final ResourceBundle RESOURCE_BUNDLE = ResourceBundle.getBundle(BUNDLE_NAME); - - private Messages() - { - // Empty. - } - - public static String getString(String key) - { - try - { - return RESOURCE_BUNDLE.getString(key); - } - catch (MissingResourceException e) - { - return '!' + key + '!'; - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.properties b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.properties deleted file mode 100644 index 3b1b327ac5e..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/Messages.properties +++ /dev/null @@ -1,43 +0,0 @@ -############################################################################### -# Copyright (c) 2006 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: -# Wind River Systems, Inc. - initial implementation -############################################################################### -TerminalConsts.Terminal_7=Terminal -TerminalConsts.Limit_terminal_output_16=Limit terminal output -TerminalConsts.Terminal_buffer_lines__17=Terminal buffer lines: -TerminalConsts.Serial_timeout_(seconds)__18=Serial timeout (seconds): -TerminalConsts.Network_timeout_(seconds)__19=Network timeout (seconds): -TerminalConsts.Terminal_Settings_1=Terminal Settings -TerminalConsts.Connection_Type_2=Connection Type -TerminalConsts.Settings_3=Settings -TerminalConsts.Port_4=Port -TerminalConsts.Baud_Rate_5=Baud Rate -TerminalConsts.Data_Bits_6=Data Bits -TerminalConsts.Stop_Bits_7=Stop Bits -TerminalConsts.Parity_8=Parity -TerminalConsts.Flow_Out_10=Flow Out -TerminalConsts.Host_11=Host -TerminalConsts.Terminal_Error_12=Terminal Error -TerminalConsts.Socket_Error_13=Socket Error -TerminalConsts.IO_Error_14=IO Error -TerminalConsts.Serial_port___{0}___is_currently_in_use_!_nDo_you_want_to_close_the_port__15=Serial port \''{0}\'' is currently in use\!\nDo you want to close the port? -TerminalConsts.Error_16=Error -TerminalConsts.Emulator_is_not_supported._17=Emulator is not supported. - -TerminalConsts.New_terminal=New Terminal -TerminalConsts.Connect_2=Connect -TerminalConsts.Disconnect_3=Disconnect -TerminalConsts.Settings..._4=Settings... -TerminalConsts.Copy_5=Copy -TerminalConsts.0=Cut -TerminalConsts.1=Flow Control -TerminalConsts.Paste_6=Paste -TerminalConsts.Select_All_7=Select All -TerminalConsts.Clear_All_8=Clear All -TerminalConsts.Break_9=Break diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetConnection.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetConnection.java deleted file mode 100644 index 745419b7cd0..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetConnection.java +++ /dev/null @@ -1,796 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - - -package org.eclipse.tm.terminal; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.Socket; -import java.net.SocketException; - -import org.eclipse.swt.widgets.Display; - - -/** - * This class encapsulates a TELNET connection to a remote server. It processes - * incoming TELNET protocol data and generates outbound TELNET protocol data. It also - * manages two sets of TelnetOption objects: one for the local endpoint and one for the - * remote endpoint.

- * - * IMPORTANT: Understanding this code requires understanding the TELNET protocol and - * TELNET option processing, as defined in the RFCs listed below.

- * - * @author Fran Litterio (francis.litterio@windriver.com) - * - * @see RFC 854 - * @see RFC 855 - * @see RFC 856 - * @see RFC 857 - * @see RFC 858 - * @see RFC 859 - * @see RFC 860 - * @see RFC 861 - * @see RFC 1091 - * @see RFC 1096 - * @see RFC 1073 - * @see RFC 1079 - * @see RFC 1143 - * @see RFC 1572 - */ -class TelnetConnection extends Thread implements TelnetCodes, TerminalMsg -{ - /** - * TELNET connection state: Initial state. - */ - protected static final int STATE_INITIAL = 0; - - /** - * TELNET connection state: Last byte processed was IAC code. - * code. - */ - protected static final int STATE_IAC_RECEIVED = 1; - - /** - * TELNET connection state: Last byte processed was WILL code. - * code. - */ - protected static final int STATE_WILL_RECEIVED = 2; - - /** - * TELNET connection state: Last byte processed was WONT code. - */ - protected static final int STATE_WONT_RECEIVED = 3; - - /** - * TELNET connection state: Last byte processed was DO code. - */ - protected static final int STATE_DO_RECEIVED = 4; - - /** - * TELNET connection state: Last byte processed was DONT code. - */ - protected static final int STATE_DONT_RECEIVED = 5; - - /** - * TELNET connection state: Last byte processed was SB. - */ - protected static final int STATE_SUBNEGOTIATION_STARTED = 6; - - /** - * TELNET connection state: Currently receiving sub-negotiation data. - */ - protected static final int STATE_RECEIVING_SUBNEGOTIATION = 7; - - /** - * Size of buffer for processing data received from remote endpoint. - */ - protected static final int BUFFER_SIZE = 2048; - - /** - * Holds raw bytes received from the remote endpoint, prior to any TELNET protocol - * processing. - */ - protected byte[] rawBytes = new byte[BUFFER_SIZE]; - - /** - * Holds incoming network data after the TELNET protocol bytes have been - * processed and removed. - */ - protected byte[] processedBytes = new byte[BUFFER_SIZE]; - - /** - * This field holds a StringBuffer containing text recently received from the - * remote endpoint (after all TELNET protocol bytes have been processed and - * removed). - */ - protected StringBuffer processedStringBuffer = new StringBuffer(BUFFER_SIZE); - - /** - * Holds the current state of the TELNET protocol processor. - */ - protected int telnetState = STATE_INITIAL; - - /** - * This field is true if the remote endpoint is a TELNET server, false if not. We - * set this to true if and only if the remote endpoint sends recognizable TELNET - * protocol data. We do not assume that the remote endpoint is a TELNET server - * just because it is listening on port 23. This allows us to successfully connect - * to a TELNET server listening on a port other than 23.

- * - * When this field first changes from false to true, we send all WILL or DO - * commands to the remote endpoint.

- * - * @see #telnetServerDetected() - */ - protected boolean remoteIsTelnetServer = false; - - /** - * An array of TelnetOption objects representing the local endpoint's TELNET - * options. The array is indexed by the numeric TELNET option code. - */ - protected TelnetOption[] localOptions = new TelnetOption[256]; - - /** - * An array of TelnetOption objects representing the remote endpoint's TELNET - * options. The array is indexed by the numeric TELNET option code. - */ - protected TelnetOption[] remoteOptions = new TelnetOption[256]; - - /** - * An array of bytes that holds the TELNET subnegotiation command most recently - * received from the remote endpoint. This array does _not_ include the leading - * IAC SB bytes, nor does it include the trailing IAC SE bytes. The first byte of - * this array is always a TELNET option code. - */ - protected byte[] receivedSubnegotiation = new byte[128]; - - /** - * This field holds the index into array {@link receivedSubnegotiation} of the next - * unused byte. This is used by method {@link #processTelnetProtocol(int)} when - * the state machine is in states {@link #STATE_SUBNEGOTIATION_STARTED} and {@link - * STATE_RECEIVING_SUBNEGOTIATION}. - */ - protected int nextSubnegotiationByteIndex = 0; - - /** - * This field is true if an error occurs while processing a subnegotiation - * command. - * - * @see #processTelnetProtocol(int) - */ - protected boolean ignoreSubnegotiation = false; - - /** - * This field holds the width of the Terminal screen in columns. - */ - protected int width = 0; - - /** - * This field holds the height of the Terminal screen in rows. - */ - protected int height = 0; - - /** - * This field holds a reference to the {@link TerminalCtrl} singleton. - */ - protected TerminalCtrl terminalControl; - - /** - * This method holds the Socket object for the TELNET connection. - */ - protected Socket socket; - - /** - * This field holds a reference to a {@link TerminalText} object, which displays - * text to the user. - */ - protected TerminalText terminalText; - - /** - * This field holds a reference to an {@link InputStream} object used to receive - * data from the remote endpoint. - */ - protected InputStream inputStream; - - /** - * This field holds a reference to an {@link OutputStream} object used to send data - * to the remote endpoint. - */ - protected OutputStream outputStream; - - /** - * This field holds the SWT Display object for the GUI. We use this to execute a - * TerminalText method on the display thread, so that it can draw text in the view. - */ - protected Display display; - - /** - * UNDER CONSTRUCTION - */ - protected boolean localEcho = true; - - /** - * This constructor just initializes some internal object state from its - * arguments. - */ - public TelnetConnection(TerminalCtrl terminalControl, Socket socket, - TerminalText terminalText) - throws IOException - { - super(); - - Logger.log("entered"); //$NON-NLS-1$ - - this.terminalControl = terminalControl; - this.socket = socket; - this.terminalText = terminalText; - - inputStream = socket.getInputStream(); - outputStream = socket.getOutputStream(); - display = terminalControl.getTextWidget().getDisplay(); - - initializeOptions(); - } - - /** - * Returns true if the TCP connection represented by this object is connected, - * false otherwise. - */ - public boolean isConnected() - { - return socket != null && socket.isConnected(); - } - - /** - * Returns true if the TCP connection represented by this object is connected and - * the remote endpoint is a TELNET server, false otherwise. - */ - public boolean isRemoteTelnetServer() - { - return remoteIsTelnetServer; - } - - /** - * This method sets the terminal width and height to the supplied values. If - * either new value differs from the corresponding old value, we initiate a NAWS - * subnegotiation to inform the remote endpoint of the new terminal size. - */ - public void setTerminalSize(int newWidth, int newHeight) - { - Logger.log("Setting new size: width = " + newWidth + ", height = " + newHeight); //$NON-NLS-1$ //$NON-NLS-2$ - - boolean sizeChanged = false; - - if (newWidth != width || newHeight != height) - sizeChanged = true; - - width = newWidth; - height = newHeight; - - if (sizeChanged && remoteIsTelnetServer && localOptions[TELNET_OPTION_NAWS].isEnabled()) - { - Integer[] sizeData = { new Integer(width), new Integer(height) }; - - localOptions[TELNET_OPTION_NAWS].sendSubnegotiation(sizeData); - } - } - - /** - * Returns true if local echoing is enabled for this TCP connection, false otherwise. - */ - public boolean localEcho() - { - return localEcho; - } - - /** - * This method runs in its own thread. It reads raw bytes from the TELNET - * connection socket, processes any TELNET protocol bytes (and removes them), and - * passes the remaining bytes to a TerminalDisplay object for display. - */ - public void run() - { - Logger.log("Entered"); //$NON-NLS-1$ - - try - { - while (socket.isConnected()) - { - int nRawBytes = inputStream.read(rawBytes); - - if (nRawBytes == -1) - { - // End of input on inputStream. - Logger.log("End of input reading from socket!"); //$NON-NLS-1$ - - // Announce to the user that the remote endpoint has closed the - // connection. - - processedStringBuffer.replace(0, processedStringBuffer.length(), - "\rConnection closed by foreign host.\r\n"); //$NON-NLS-1$ - - terminalText.setNewText(processedStringBuffer); - - // See the large comment below for an explaination of why we must - // call Display.syncExec() instead of Display.asyncExec(). - - display.syncExec(terminalText); - - // Tell the TerminalCtrl object that the connection is closed. - - terminalControl.setOpened(false); - terminalControl.setConnected(false); - - // Update the Terminal view UI to show a disconnected state. This - // ugliness involving Display.asyncExec() is forced on us by the - // bad design of class TerminalCtrl, which requires in certain - // cases (maybe all?) that TerminalCtrl.execute() is called only - // from the display thread. - - Runnable disconnectNotifier = new Thread() - { - public void run() - { - terminalControl.execute(ON_TERMINAL_DISCONNECT, null); - } - }; - - display.asyncExec(disconnectNotifier); - break; - } - else - { - Logger.log("Received " + nRawBytes + " bytes: '" + //$NON-NLS-1$ //$NON-NLS-2$ - new String(rawBytes, 0, nRawBytes) + "'"); //$NON-NLS-1$ - - // Process any TELNET protocol data that we receive. Don't send - // any TELNET protocol data until we are sure the remote endpoint - // is a TELNET server. - - int nProcessedBytes = processTelnetProtocol(nRawBytes); - - if (nProcessedBytes > 0) - { - String strBuffer = new String(processedBytes, 0, nProcessedBytes); - - // An earlier version of this code created a new StringBuffer - // object here, but that was unnecessary. Instead, we reuse an - // existing object (processedStringBuffer). - - processedStringBuffer.replace(0, processedStringBuffer.length(), - strBuffer); - - // Use the TerminalText object to display the text to the - // user. - - terminalText.setNewText(processedStringBuffer); - - // Now make the TerminalText object display the processesed - // bytes. Its code has to run in the display thread, so we - // call syncExec() to do that. We do _not_ call asyncExec() - // because asyncExec() does not wait for the Runnable - // (TerminalText) to finish. If we were to call asynchExec(), - // this loop might race around and call setNewText() on the - // terminalText object again before the Display thread gets to - // display the previous buffer held by that object. By - // blocking here, we avoid that race and also delay the next - // call to read(), which keeps the unread data in the kernel, - // where it belongs (i.e., we don't have to manage it). - // - // - // The original implementation of this package used asyncExec() - // and created a new TerminalText object for each trip through - // this loop. Yes, that allowed this thread to speed ahead of - // the Display thread. But that only served to make the - // Display thread queue all unexecuted TerminalText objects - // until they could be executed. That was simply buffering the - // undisplayed data in the Display thread instead of in the - // kernel, where it belongs. It also rapidly consumed JVM heap - // space with all those TerminalText objects waiting to be - // garbage collected. - // - - display.syncExec(terminalText); - } - } - } - } - catch (SocketException ex) - { - String message = ex.getMessage(); - - // A "socket closed" exception is normal here. It's caused by the user - // clicking the disconnect button on the Terminal view toolbar. - - if (message != null && !message.equals("socket closed")) //$NON-NLS-1$ - { - Logger.logException(ex); - } - } - catch (Exception ex) - { - Logger.logException(ex); - } - } - - /** - * This method initializes the localOptions[] and remoteOptions[] arrays so that - * they contain references to TelnetOption objects representing our desired state - * for each option. The goal is to achieve server-side echoing, suppression of Go - * Aheads, and to send the local terminal type and size to the remote endpoint. - */ - protected void initializeOptions() - { - // First, create all the TelnetOption objects in the "undesired" state. - - for (int i = 0; i < localOptions.length; ++i) - { - localOptions[i] = new TelnetOption((byte)i, false, true, outputStream); - } - - for (int i = 0; i < localOptions.length; ++i) - { - remoteOptions[i] = new TelnetOption((byte)i, false, false, outputStream); - } - - // Next, set some of the options to the "desired" state. The options we desire - // to be enabled are as follows: - // - // TELNET Option Desired for Desired for - // Name and Code Local Endpoint Remote Endpoint - // --------------------- -------------- --------------- - // Echo (1) No Yes - // Suppress Go Ahead (3) Yes Yes - // Terminal Type (24) Yes Yes - // NAWS (31) Yes Yes - // - // All other options remain in the "undesired" state, and thus will be disabled - // (since either endpoint can force any option to be disabled by simply - // answering WILL with DONT and DO with WONT). - - localOptions[TELNET_OPTION_ECHO].setDesired(false); - remoteOptions[TELNET_OPTION_ECHO].setDesired(true); - - localOptions[TELNET_OPTION_SUPPRESS_GA].setDesired(true); - remoteOptions[TELNET_OPTION_SUPPRESS_GA].setDesired(true); - - localOptions[TELNET_OPTION_TERMINAL_TYPE].setDesired(true); - remoteOptions[TELNET_OPTION_TERMINAL_TYPE].setDesired(true); - - localOptions[TELNET_OPTION_NAWS].setDesired(true); - remoteOptions[TELNET_OPTION_NAWS].setDesired(true); - } - - /** - * Process TELNET protocol data contained in the first count bytes of - * rawBytes. This function preserves its state between calls, because a - * multi-byte TELNET command might be split between two (or more) calls to this - * function. The state is preserved in field telnetState. This function - * implements an FSA that recognizes TELNET option codes. TELNET option state is - * stored in instances of {@link TelnetOption}. TELNET option subnegotiation is - * delegated to instances of TelnetOption. - * - * @return The number of bytes remaining in the buffer after removing all TELNET - * protocol bytes. - */ - protected int processTelnetProtocol(int count) - { - // This is too noisy to leave on all the time. - // Logger.log("Processing " + count + " bytes of data."); - - int nextProcessedByte = 0; - - for (int byteIndex = 0; byteIndex < count; ++byteIndex) - { - // It is possible for control to flow through the below code such that - // nothing happens. This happens when array rawBytes[] contains no TELNET - // protocol data. - - byte inputByte = rawBytes[byteIndex]; - - switch (telnetState) - { - case STATE_INITIAL: - if (inputByte == TELNET_IAC) - { - telnetState = STATE_IAC_RECEIVED; - } - else - { - // It's not an IAC code, so just append it to processedBytes. - - processedBytes[nextProcessedByte++] = rawBytes[byteIndex]; - } - break; - - case STATE_IAC_RECEIVED: - switch (inputByte) - { - case TELNET_IAC: - // Two IAC bytes in a row are translated into one byte with the - // value 0xff. - - processedBytes[nextProcessedByte++] = (byte)0xff; - telnetState = STATE_INITIAL; - break; - - case TELNET_WILL: - telnetState = STATE_WILL_RECEIVED; - break; - - case TELNET_WONT: - telnetState = STATE_WONT_RECEIVED; - break; - - case TELNET_DO: - telnetState = STATE_DO_RECEIVED; - break; - - case TELNET_DONT: - telnetState = STATE_DONT_RECEIVED; - break; - - case TELNET_SB: - telnetState = STATE_SUBNEGOTIATION_STARTED; - break; - - // Commands to consume and ignore. - - // Data Mark (DM). This is sent by a TELNET server following an - // IAC sent as TCP urgent data. It should cause the client to skip - // all not yet processed non-TELNET-protocol data preceding the DM - // byte. However, Java 1.4.x has no way to inform clients of class - // Socket that urgent data is available, so we simply ignore the - // "IAC DM" command. Since the IAC is sent as TCP urgent data, the - // Socket must be put into OOB-inline mode via a call to - // setOOBInline(true), otherwise the IAC is silently dropped by - // Java and only the DM arrives (leaving the user to see a spurious - // ISO Latin-1 character). - case TELNET_DM: - - case TELNET_NOP: // No-op. - case TELNET_GA: // Go Ahead command. Meaningless on a full-duplex link. - case TELNET_IP: // Interupt Process command. Server should never send this. - case TELNET_AO: // Abort Output command. Server should never send this. - case TELNET_AYT: // Are You There command. Server should never send this. - case TELNET_EC: // Erase Character command. Server should never send this. - case TELNET_EL: // Erase Line command. Server should never send this. - telnetState = STATE_INITIAL; - break; - - default: - // Unrecognized command! This should never happen. - Logger.log("processTelnetProtocol: UNRECOGNIZED TELNET PROTOCOL COMMAND: " + //$NON-NLS-1$ - inputByte); - telnetState = STATE_INITIAL; - assert false; - break; - } - break; - - // For the next four cases, WILL and WONT commands affect the state of - // remote options, and DO and DONT commands affect the state of local - // options. - - case STATE_WILL_RECEIVED: - Logger.log("Received WILL " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - remoteOptions[inputByte].handleWill(); - telnetState = STATE_INITIAL; - telnetServerDetected(); - break; - - case STATE_WONT_RECEIVED: - Logger.log("Received WONT " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - remoteOptions[inputByte].handleWont(); - telnetState = STATE_INITIAL; - telnetServerDetected(); - break; - - case STATE_DO_RECEIVED: - Logger.log("Received DO " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - localOptions[inputByte].handleDo(); - telnetState = STATE_INITIAL; - telnetServerDetected(); - break; - - case STATE_DONT_RECEIVED: - Logger.log("Received DONT " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - localOptions[inputByte].handleDont(); - telnetState = STATE_INITIAL; - telnetServerDetected(); - break; - - case STATE_SUBNEGOTIATION_STARTED: - Logger.log("Starting subnegotiation for option " + //$NON-NLS-1$ - localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ - - // First, zero out the array of received subnegotiation butes. - - for (int i = 0; i < receivedSubnegotiation.length; ++i) - receivedSubnegotiation[i] = 0; - - // Forget about any previous subnegotiation errors. - - ignoreSubnegotiation = false; - - // Then insert this input byte into the array and enter state - // STATE_RECEIVING_SUBNEGOTIATION, where we will gather the remaining - // subnegotiation bytes. - - nextSubnegotiationByteIndex = 0; - receivedSubnegotiation[nextSubnegotiationByteIndex++] = inputByte; - telnetState = STATE_RECEIVING_SUBNEGOTIATION; - break; - - case STATE_RECEIVING_SUBNEGOTIATION: - if (inputByte == TELNET_IAC) - { - // Handle double IAC bytes. From RFC 855: "if parameters - // in an option 'subnegotiation' include a byte with a value of - // 255, it is necessary to double this byte in accordance the - // general TELNET rules." - - if (nextSubnegotiationByteIndex > 0 && - receivedSubnegotiation[nextSubnegotiationByteIndex - 1] == TELNET_IAC) - { - // The last input byte we received in this subnegotiation was - // IAC, so this is a double IAC. Leave the previous IAC in the - // receivedSubnegotiation[] array and drop the current one - // (thus translating a double IAC into a single IAC). - - Logger.log("Double IAC in subnegotiation translated into single IAC."); //$NON-NLS-1$ - break; - } - - // Append the IAC byte to receivedSubnegotiation[]. If there is no - // room for the IAC byte, it overwrites the last byte, because we - // need to know when the subnegotiation ends, and that is marked by - // an "IAC SE" command. - - if (nextSubnegotiationByteIndex < receivedSubnegotiation.length) - { - receivedSubnegotiation[nextSubnegotiationByteIndex++] = inputByte; - } - else - { - receivedSubnegotiation[receivedSubnegotiation.length - 1] = inputByte; - } - break; - } - - // Handle an "IAC SE" command, which marks the end of the - // subnegotiation. An SE byte by itself might be a legitimate part of - // the subnegotiation data, so don't do anything unless the SE is - // immediately preceded by an IAC. - - if (inputByte == TELNET_SE && - receivedSubnegotiation[nextSubnegotiationByteIndex - 1] == TELNET_IAC) - { - Logger.log("Found SE code marking end of subnegotiation."); //$NON-NLS-1$ - - // We are done receiving the subnegotiation command. Now process - // it. We always use the option object stored in array - // localOptions[] to process the received subnegotiation. This is - // an arbitrary decision, but it is sufficient for handling options - // TERMINAL-TYPE and NAWS, which are the only options that we - // subnegotiate (presently). If, in the future, subnegotiations - // need to be handled by option objects stored in both - // localOptions[] and remoteOptions[], then some mechanism to - // choose the correct option object must be implemented. - // - // Also, if ignoreSubnegotiation is true, there was an error while - // receiving the subnegotiation, so we must not process the - // command, and instead just return to the initial state. - - if (!ignoreSubnegotiation) - { - // Remove the trailing IAC byte from receivedSubnegotiation[]. - - receivedSubnegotiation[nextSubnegotiationByteIndex - 1] = 0; - - int subnegotiatedOption = receivedSubnegotiation[0]; - - localOptions[subnegotiatedOption]. - handleSubnegotiation(receivedSubnegotiation, - nextSubnegotiationByteIndex); - } - else - { - Logger.log("NOT CALLING handleSubnegotiation() BECAUSE OF ERRORS!"); //$NON-NLS-1$ - } - - // Return to the initial state. - - telnetState = STATE_INITIAL; - } - - // Check whether the receivedSubnegotiation[] array is full. - - if (nextSubnegotiationByteIndex >= receivedSubnegotiation.length) - { - // This should not happen. Array receivedSubnegotiation can hold - // 128 bytes, and no TELNET option that we perform subnegotiation - // for requires that many bytes in a subnegotiation command. In - // the interest of robustness, we handle this case by ignoring all - // remaining subnegotiation bytes until we receive the IAC SE - // command that ends the subnegotiation. Also, we set - // ignoreSubnegotiation to true to prevent a call to - // handleSubnegotiation() when the IAC SE command arrives. - - Logger.log("SUBNEGOTIATION BUFFER FULL!"); //$NON-NLS-1$ - ignoreSubnegotiation = true; - } - else - { - Logger.log("Recording subnegotiation byte " + (inputByte & 0xff)); //$NON-NLS-1$ - - receivedSubnegotiation[nextSubnegotiationByteIndex++] = inputByte; - } - break; - - default: - // This should _never_ happen! If it does, it means there is a bug in - // this FSA. For robustness, we return to the initial state. - - Logger.log("INVALID TELNET STATE: " + telnetState); //$NON-NLS-1$ - telnetState = STATE_INITIAL; - assert false; - break; - } - } - - // Return the number of bytes of processed data (i.e., number of bytes of - // raw data minus TELNET control bytes). This value can be zero. - - return nextProcessedByte; - } - - /** - * This method is called whenever we receive a valid TELNET protocol command from - * the remote endpoint. When it is called for the first time for this connection, - * we negotiate all options that we desire to be enabled.

- * - * This method does not negotiate options that we do not desire to be enabled, - * because all options are initially disabled.

- */ - protected void telnetServerDetected() - { - if (!remoteIsTelnetServer) - { - // This block only executes once per TelnetConnection instance. - - localEcho = false; - - Logger.log("Detected TELNET server."); //$NON-NLS-1$ - - remoteIsTelnetServer = true; - - for (int i = 0; i < localOptions.length; ++i) - { - if (localOptions[i].isDesired()) - { - localOptions[i].negotiate(); - } - } - - for (int i = 0; i < remoteOptions.length; ++i) - { - if (remoteOptions[i].isDesired()) - { - remoteOptions[i].negotiate(); - } - } - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetOption.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetOption.java deleted file mode 100644 index 60712d6eeef..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetOption.java +++ /dev/null @@ -1,756 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - - -package org.eclipse.tm.terminal; - -import java.io.IOException; -import java.io.OutputStream; -import java.util.Date; - -/** - * This class represents a single TELNET protocol option at one endpoint of a TELNET - * connection. This class encapsulates the endpoint associated with the option (local - * or remote), the current state of the option (enabled or disabled), the desired state - * of the option, the current state of the negotiation, an OutputStream that allows - * communication with the remote endpoint, and the number of negotiations that have - * started within this connection.

- * - * In addition to encapsulating the above state, this class performs option negotiation - * to attempt to achieve the desired option state. For some options, this class also - * performs option sub-negotiation.

- * - * IMPORTANT: Understanding this code requires understanding the TELNET protocol and - * TELNET option processing.

- * - * @author Fran Litterio (francis.litterio@windriver.com) - */ -class TelnetOption implements TelnetCodes -{ - /** - * This array of Strings maps an integer TELNET option code value to the symbolic - * name of the option. Array elements of the form "?" represent unassigned option - * values. - */ - protected static final String[] optionNames = - { - "BINARY", // 0 //$NON-NLS-1$ - "ECHO", // 1 //$NON-NLS-1$ - "RECONNECTION", // 2 //$NON-NLS-1$ - "SUPPRESS GO AHEAD", // 3 //$NON-NLS-1$ - "MSG SIZE NEGOTIATION", // 4 //$NON-NLS-1$ - "STATUS", // 5 //$NON-NLS-1$ - "TIMING MARK", // 6 //$NON-NLS-1$ - "REMOTE CTRL TRANS+ECHO", // 7 //$NON-NLS-1$ - "OUTPUT LINE WIDTH", // 8 //$NON-NLS-1$ - "OUTPUT PAGE SIZE", // 9 //$NON-NLS-1$ - "OUTPUT CR DISPOSITION", // 10 //$NON-NLS-1$ - "OUTPUT HORIZ TABSTOPS", // 11 //$NON-NLS-1$ - "OUTPUT HORIZ TAB DISPOSITION", // 12 //$NON-NLS-1$ - "OUTPUT FORMFEED DISPOSITION", // 13 //$NON-NLS-1$ - "OUTPUT VERTICAL TABSTOPS", // 14 //$NON-NLS-1$ - "OUTPUT VT DISPOSITION", // 15 //$NON-NLS-1$ - "OUTPUT LF DISPOSITION", // 16 //$NON-NLS-1$ - "EXTENDED ASCII", // 17 //$NON-NLS-1$ - "LOGOUT", // 18 //$NON-NLS-1$ - "BYTE MACRO", // 19 //$NON-NLS-1$ - "DATA ENTRY TERMINAL", // 20 //$NON-NLS-1$ - "SUPDUP", // 21 //$NON-NLS-1$ - "SUPDUP OUTPUT", // 22 //$NON-NLS-1$ - "SEND LOCATION", // 23 //$NON-NLS-1$ - "TERMINAL TYPE", // 24 //$NON-NLS-1$ - "END OF RECORD", // 25 //$NON-NLS-1$ - "TACACS USER IDENTIFICATION", // 26 //$NON-NLS-1$ - "OUTPUT MARKING", // 27 //$NON-NLS-1$ - "TERMINAL LOCATION NUMBER", // 28 //$NON-NLS-1$ - "3270 REGIME", // 29 //$NON-NLS-1$ - "X.3 PAD", // 30 //$NON-NLS-1$ - "NEGOTIATE ABOUT WINDOW SIZE", // 31 //$NON-NLS-1$ - "TERMINAL SPEED", // 32 //$NON-NLS-1$ - "REMOTE FLOW CONTROL", // 33 //$NON-NLS-1$ - "LINEMODE", // 34 //$NON-NLS-1$ - "X DISPLAY LOCATION", // 35 //$NON-NLS-1$ - "ENVIRONMENT OPTION", // 36 //$NON-NLS-1$ - "AUTHENTICATION OPTION", // 37 //$NON-NLS-1$ - "ENCRYPTION OPTION", // 38 //$NON-NLS-1$ - "NEW ENVIRONMENT OPTION", // 39 //$NON-NLS-1$ - "TN3270E", // 40 //$NON-NLS-1$ - "XAUTH", // 41 //$NON-NLS-1$ - "CHARSET", // 42 //$NON-NLS-1$ - "REMOTE SERIAL PORT", // 43 //$NON-NLS-1$ - "COM PORT CONTROL OPTION", // 44 //$NON-NLS-1$ - "SUPPRESS LOCAL ECHO", // 45 //$NON-NLS-1$ - "START TLS", // 46 //$NON-NLS-1$ - "KERMIT", // 47 //$NON-NLS-1$ - "SEND URL", // 48 //$NON-NLS-1$ - "FORWARD X", // 49 //$NON-NLS-1$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 50 ... //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", // ... 137 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ - "TELOPT PRAGMA LOGON", // 138 //$NON-NLS-1$ - "TELOPT SSPI LOGON", // 139 //$NON-NLS-1$ - "TELOPT PRAGMA HEARTBEAT", // 140 //$NON-NLS-1$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 141 ... //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ - "?", "?", "?", "?", // ... 254 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - "EXTENDED OPTIONS LIST" // 255 //$NON-NLS-1$ - }; - - /** - * Negotiation state: Negotiation not yet started for this option.

- * - * This constant and the others having similar names represent the states of a - * finite state automaton (FSA) that tracks the negotiation state of this option. - * The initial state is NEGOTIATION_NOT_STARTED. The state machine is as follows - * (with transitions labelled with letters in parentheses):

- * - *

-     *     NEGOTIATION_NOT_STARTED -----> {@link #NEGOTIATION_IN_PROGRESS}
-     *                         |    (A)      |        ^
-     *                      (C)|          (B)|        |(D)
-     *                         |             V        |
-     *                         +--------> {@link #NEGOTIATION_DONE}
-     * 

- * - * Once the FSA leaves state NEGOTIATION_NOT_STARTED, it never returns to that - * state. Transition A happens when the local endpoint sends an option command - * before receiving a command for the same option from the remote endpoint.

- * - * Transition B happens when the local endpoint receives a reply to an option - * command sent earlier by the local endpoint. Receipt of that reply terminates - * the negotiation.

- * - * Transition D happens after negotiation is done and "something changes" (see the - * RFCs for the definition of "something changes"). Either endpoint can - * re-negotiate an option after a previous negotiation, but only if some external - * influence (such as the user or the OS) causes it to do so. Re-negotiation must - * start more than {@link #NEGOTIATION_IGNORE_DURATION} milliseconds after the FSA - * enters state NEGOTIATION_DONE or it will be ignored. This is how this client - * prevents negotiation loops.

- * - * Transition C happens when the local endpoint receives an option command from the - * remote endpoint before sending a command for the same option. In that case, the - * local endpoint replies immediately with an option command and the negotitation - * terminates.

- * - * Some TELNET servers (e.g., the Solaris server), after sending WILL and receiving - * DONT, will reply with a superfluous WONT. Any such superfluous option command - * received from the remote endpoint while the option's FSA is in state - * {@link #NEGOTIATION_DONE} will be ignored by the local endpoint. - */ - protected static final int NEGOTIATION_NOT_STARTED = 0; - - /** Negotiation state: Negotiation is in progress for this option. */ - protected static final int NEGOTIATION_IN_PROGRESS = 1; - - /** Negotiation state: Negotiation has terminated for this option. */ - protected static final int NEGOTIATION_DONE = 2; - - /** - * The number of milliseconds following the end of negotiation of this option - * before which the remote endpoint can re-negotiate the option. Any option - * command received from the remote endpoint before this time passes is ignored. - * This is used to prevent option negotiation loops. - * - * @see #ignoreNegotiation() - * @see #negotiationCompletionTime - */ - protected static final int NEGOTIATION_IGNORE_DURATION = 30000; - - /** - * This field holds the current negotiation state for this option. - */ - protected int negotiationState = NEGOTIATION_NOT_STARTED; - - /** - * This field holds the time when negotiation of this option most recently - * terminated (i.e., entered state {@link #NEGOTIATION_DONE}). This is used to - * determine whether an option command received from the remote endpoint after - * negotiation has terminated for this option is to be ignored or interpreted as - * the start of a new negotiation. - * - * @see #NEGOTIATION_IGNORE_DURATION - */ - protected Date negotiationCompletionTime = new Date(0); - - /** - * Holds the total number of negotiations that have completed for this option. - */ - protected int negotiationCount = 0; - - /** - * Holds the integer code representing the option. - */ - protected byte option = 0; - - /** - * Holds the OutputStream object that allows data to be sent to the remote endpoint - * of the TELNET connection. - */ - protected OutputStream outputStream; - - /** - * True if this option is for the local endpoint, false for the remote endpoint. - */ - protected boolean local = true; - - /** - * This field is true if the option is enabled, false if it is disabled. All - * options are initially disabled until they are negotiated to be enabled.

- */ - protected boolean enabled = false; - - /** - * This field is true if the client desires the option to be enabled, false if the - * client desires the option to be disabled. This field does not represent the - * remote's endpoints desire (as expressed via WILL and WONT commands) -- it - * represnet the local endpoint's desire.

- * - * @see #setDesired(boolean) - */ - protected boolean desired = false; - - /** - * Constructor.

- * - * @param option The integer code of this option. - * @param desired Whether we desire this option to be enabled. - * @param local Whether this option is for the local or remote endpoint. - * @param outputStream A stream used to negotiate with the remote endpoint. - */ - TelnetOption(byte option, boolean desired, boolean local, OutputStream outputStream) - { - this.option = option; - this.desired = desired; - this.local = local; - this.outputStream = outputStream; - } - - /** - * @return Returns a String containing the name of the TELNET option specified in - * parameter option. - */ - public String optionName() - { - return optionNames[option]; - } - - /** - * Returns true if this option is enabled, false if it is disabled.

- * - * @return Returns true if this option is enabled, false if it is disabled. - */ - public boolean isEnabled() - { - return enabled; - } - - /** - * Enables this option if newValue is true, otherwise disables this - * option.

- * - * @param newValue True if this option is to be enabled, false otherwise. - */ - public void setEnabled(boolean newValue) - { - Logger.log("Enabling " + (local ? "local" : "remote") + " option " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - optionName()); - enabled = newValue; - } - - /** - * Returns true if the local endpoint desires this option to be enabled, false if - * not. It is not an error for the value returned by this method to differ from - * the value returned by isEnabled(). The value returned by this method can change - * over time, reflecting the local endpoint's changing desire regarding the - * option.

- * - * NOTE: Even if this option represents a remote endpoint option, the return value - * of this method represents the local endpint's desire regarding the remote - * option.

- * - * @return Returns true if the local endpoint desires this option to be enabled, - * false if not. - */ - public boolean isDesired() - { - return desired; - } - - /** - * Sets our desired value for this option. Note that the option can be desired - * when enabled is false, and the option can be undesired when - * enabled is true, though the latter state should not persist, since either - * endpoint can disable any option at any time.

- * - * @param newValue True if we desire this option to be enabled, false if - * we desire this option to be disabled. - */ - public void setDesired(boolean newValue) - { - if (newValue) - Logger.log("Setting " + (local ? "local" : "remote") + " option " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - optionName() + " as desired."); //$NON-NLS-1$ - - desired = newValue; - } - - /** - * Call this method to request that negotiation begin for this option. This method - * does nothing if negotiation for this option has already started or is already - * complete. If negotiation has not yet started for this option and the local - * endpoint desires this option to be enabled, then we send a WILL or DO command to - * the remote endpoint. - */ - public void negotiate() - { - if (negotiationState == NEGOTIATION_NOT_STARTED && desired) - { - if (local) - { - Logger.log("Starting negotiation for local option " + optionName()); //$NON-NLS-1$ - sendWill(); - } - else - { - Logger.log("Starting negotiation for remote option " + optionName()); //$NON-NLS-1$ - sendDo(); - } - - negotiationState = NEGOTIATION_IN_PROGRESS; - } - } - - /** - * This method is called whenever we receive a WILL command from the remote - * endpoint. - */ - public void handleWill() - { - if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) - { - Logger.log("Ignoring superfluous WILL command from remote endpoint."); //$NON-NLS-1$ - return; - } - - if (negotiationState == NEGOTIATION_IN_PROGRESS) - { - if (desired) - { - // We sent DO and server replied with WILL. Enable the option, and end - // this negotiation. - - enabled = true; - Logger.log("Enabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - else - { - // This should never happen! We sent DONT and the server replied with - // WILL. Bad server. No soup for you. Disable the option, and end - // this negotiation. - - Logger.log("Server answered DONT with WILL!"); //$NON-NLS-1$ - enabled = false; - Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - } - else - { - if (desired) - { - // Server sent WILL, so we reply with DO. Enable the option, and end - // this negotiation. - - sendDo(); - enabled = true; - Logger.log("Enabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - else - { - // Server sent WILL, so we reply with DONT. Disable the option, and - // end this negotiation. - - sendDont(); - enabled = false; - Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - } - } - - /** - * Handles a WONT command sent by the remote endpoint for this option. The value - * of desired doesn't matter in this method, because the remote endpoint is - * forcing the option to be disabled. - */ - public void handleWont() - { - if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) - { - Logger.log("Ignoring superfluous WONT command from remote endpoint."); //$NON-NLS-1$ - return; - } - - if (negotiationState == NEGOTIATION_IN_PROGRESS) - { - // We sent DO or DONT and server replied with WONT. Disable the - // option, and end this negotiation. - - enabled = false; - Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - else - { - // Server sent WONT, so we reply with DONT. Disable the option, and - // end this negotiation. - - sendDont(); - enabled = false; - Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - } - - /** - * Handles a DO command sent by the remote endpoint for this option. - */ - public void handleDo() - { - if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) - { - Logger.log("Ignoring superfluous DO command from remote endpoint."); //$NON-NLS-1$ - return; - } - - if (negotiationState == NEGOTIATION_IN_PROGRESS) - { - if (desired) - { - // We sent WILL and server replied with DO. Enable the option, and end - // this negotiation. - - enabled = true; - Logger.log("Enabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - else - { - // We sent WONT and server replied with DO. This should never happen! - // Bad server. No soup for you. Disable the option, and end this - // negotiation. - - Logger.log("Server answered WONT with DO!"); //$NON-NLS-1$ - enabled = false; - Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - } - else - { - if (desired) - { - // Server sent DO, so we reply with WILL. Enable the option, and end - // this negotiation. - - sendWill(); - enabled = true; - Logger.log("Enabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - else - { - // Server sent DO, so we reply with WONT. Disable the option, and end - // this negotiation. - - sendWont(); - enabled = false; - Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - } - } - - /** - * Handles a DONT command sent by the remote endpoint for this option. The value - * of desired doesn't matter in this method, because the remote endpoint is - * forcing the option to be disabled. - */ - public void handleDont() - { - if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) - { - Logger.log("Ignoring superfluous DONT command from remote endpoint."); //$NON-NLS-1$ - return; - } - - if (negotiationState == NEGOTIATION_IN_PROGRESS) - { - // We sent WILL or WONT and server replied with DONT. Disable the - // option, and end this negotiation. - - enabled = false; - Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - else - { - // Server sent DONT, so we reply with WONT. Disable the option, and end - // this negotiation. - - sendWont(); - enabled = false; - Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ - endNegotiation(); - } - } - - /** - * This method handles a subnegotiation command received from the remote endpoint. - * Currently, the only subnegotiation we handle is when the remote endpoint - * commands us to send our terminal type (which is "ansi"). - * - * @param subnegotiationData An array of bytes containing a TELNET - * subnegotiation command received from the - * remote endpoint. - * @param count The number of bytes in array - * subnegotiationData to examine. - */ - public void handleSubnegotiation(byte[] subnegotiationData, int count) - { - switch (option) - { - case TELNET_OPTION_TERMINAL_TYPE: - if (subnegotiationData[1] != TELNET_SEND) - { - // This should never happen! - Logger.log("Invalid TERMINAL-TYPE subnegotiation command from remote endpoint: " + //$NON-NLS-1$ - (subnegotiationData[1] & 0xff)); - break; - } - - // Tell the remote endpoint our terminal type is "ansi" using this sequence - // of TELNET protocol bytes: - // - // IAC SB TERMINAL-TYPE IS a n s i IAC SE - - byte[] terminalTypeData = { TELNET_IAC, TELNET_SB, TELNET_OPTION_TERMINAL_TYPE, - TELNET_IS, (byte)'a', (byte)'n', (byte)'s', (byte)'i', - TELNET_IAC, TELNET_SE }; - - try - { - outputStream.write(terminalTypeData); - } - catch (IOException ex) - { - Logger.log("IOException sending TERMINAL-TYPE subnegotiation!"); //$NON-NLS-1$ - Logger.logException(ex); - } - break; - - default: - // This should never happen! - Logger.log("SHOULD NOT BE REACHED: Called for option " + optionName()); //$NON-NLS-1$ - assert false; - break; - } - } - - /** - * This method sends a subnegotiation command to the remote endpoint. - * - * @param subnegotiationData An array of Objects holding data to be used - * when generating the outbound subnegotiation - * command. - */ - public void sendSubnegotiation(Object[] subnegotiationData) - { - switch (option) - { - case TELNET_OPTION_NAWS: - // Get the width and height of the view and send it to the remote - // endpoint using this sequence of TELNET protocol bytes: - // - // IAC SB NAWS - // IAC SE - - byte[] NAWSData = { TELNET_IAC, TELNET_SB, TELNET_OPTION_NAWS, - 0, 0, 0, 0, TELNET_IAC, TELNET_SE }; - int width = ((Integer)subnegotiationData[0]).intValue(); - int height = ((Integer)subnegotiationData[1]).intValue(); - - NAWSData[3] = (byte)((width >>> 8) & 0xff); // High order byte of width. - NAWSData[4] = (byte)(width & 0xff); // Low order byte of width. - NAWSData[5] = (byte)((height >>> 8) & 0xff); // High order byte of height. - NAWSData[6] = (byte)(height & 0xff); // Low order byte of height. - - Logger.log("sending terminal size to remote endpoint: width = " + width + //$NON-NLS-1$ - ", height = " + height + "."); //$NON-NLS-1$ //$NON-NLS-2$ - - // This final local variable is a hack to get around the fact that inner - // classes cannot reference a non-final local variable in a lexically - // enclosing scope. - - final byte[] NAWSDataFinal = NAWSData; - - // Send the NAWS data in a new thread. The current thread is the display - // thread, and calls to write() can block, but blocking the display thread - // is _bad_ (it hangs the GUI). - - new Thread() - { - public void run() - { - try - { - outputStream.write(NAWSDataFinal); - } - catch (IOException ex) - { - Logger.log("IOException sending NAWS subnegotiation!"); //$NON-NLS-1$ - Logger.logException(ex); - } - } - }.start(); - break; - - default: - // This should never happen! - Logger.log("SHOULD NOT BE REACHED: Called for option " + optionName()); //$NON-NLS-1$ - assert false; - break; - } - } - - - /** - * This method returns true if there has not yet been any negotiation of this - * option. - * - * @return Returns true if there has not yet been any negotiation of this option. - */ - protected boolean notYetNegotiated() - { - return negotiationState == NEGOTIATION_NOT_STARTED; - } - - /** - * This method terminates the current negotiation and records the time at which the - * negotiation terminated. - */ - protected void endNegotiation() - { - Logger.log("Ending negotiation #" + negotiationCount + " for " + //$NON-NLS-1$ //$NON-NLS-2$ - (local ? "local" : "remote") + " option " + optionName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - negotiationState = NEGOTIATION_DONE; - negotiationCompletionTime.setTime(System.currentTimeMillis()); - ++negotiationCount; - } - - /** - * This method determines whether or not to ignore what appears to be a new - * negotiation initiated by the remote endpoint. This is needed because some - * TELNET servers send superfluous option commands that a naive client might - * interpret as the start of a new negotiation. If the superfluous command is not - * ignored, an option negotiation loop can result (which is bad). For details - * about the superfluous commands sent by some servers, see the documentation for - * {@link #NEGOTIATION_NOT_STARTED}.

- * - * The current implementation of this method returns true if the new negotiation - * starts within NEGOTIATION_IGNORE_DURATION seconds of the end of the previous - * negotiation of this option.

- * - * @return Returns true if the new negotiation should be ignored, false if not. - */ - protected boolean ignoreNegotiation() - { - return (System.currentTimeMillis() - negotiationCompletionTime.getTime()) > - NEGOTIATION_IGNORE_DURATION; - } - - /** - * Sends a DO command to the remote endpoint for this option. - */ - protected void sendDo() - { - Logger.log("Sending DO " + optionName()); //$NON-NLS-1$ - sendCommand(TELNET_DO); - } - - /** - * Sends a DONT command to the remote endpoint for this option. - */ - protected void sendDont() - { - Logger.log("Sending DONT " + optionName()); //$NON-NLS-1$ - sendCommand(TELNET_DONT); - } - - /** - * Sends a WILL command to the remote endpoint for this option. - */ - protected void sendWill() - { - Logger.log("Sending WILL " + optionName()); //$NON-NLS-1$ - sendCommand(TELNET_WILL); - } - - /** - * Sends a WONT command to the remote endpoint for this option. - */ - protected void sendWont() - { - Logger.log("Sending WONT " + optionName()); //$NON-NLS-1$ - sendCommand(TELNET_WONT); - } - - /** - * This method sends a WILL/WONT/DO/DONT command to the remote endpoint for this - * option. - */ - protected void sendCommand(byte command) - { - byte[] data = { TELNET_IAC, 0, 0 }; - - data[1] = command; - data[2] = option; - - try - { - outputStream.write(data); - } - catch (IOException ex) - { - Logger.log("IOException sending command " + command); //$NON-NLS-1$ - Logger.logException(ex); - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalAction.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalAction.java deleted file mode 100644 index e1b786d4867..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalAction.java +++ /dev/null @@ -1,119 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - - -package org.eclipse.tm.terminal; - -import org.eclipse.jface.action.Action; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.resource.ImageRegistry; - -public class TerminalAction extends Action - implements TerminalMsg, TerminalConsts -{ - /** - * - */ - protected TerminalTarget m_Target; - protected String m_strMsg; - - /** - * - */ - public TerminalAction(TerminalTarget target, - String strMsg, - String strId) - { - super(""); //$NON-NLS-1$ - - m_Target = target; - m_strMsg = strMsg; - - setId(strId); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Action interface - // - - /** - * - */ - public void run() - { - m_Target.execute(m_strMsg,this); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operations - // - - /** - * - */ - protected void setupAction(String strText, - String strToolTip, - String strImage, - String strEnabledImage, - String strDisabledImage, - boolean bEnabled) - { - TerminalPlugin plugin; - ImageRegistry imageRegistry; - - plugin = TerminalPlugin.getDefault(); - imageRegistry = plugin.getImageRegistry(); - setupAction(strText, - strToolTip, - strImage, - strEnabledImage, - strDisabledImage, - bEnabled, - imageRegistry); - } - - /** - * - */ - protected void setupAction(String strText, - String strToolTip, - String strImage, - String strEnabledImage, - String strDisabledImage, - boolean bEnabled, - ImageRegistry imageRegistry) - { - ImageDescriptor imageDescriptor; - - setText(strText); - setToolTipText(strToolTip); - setEnabled(bEnabled); - - imageDescriptor = imageRegistry.getDescriptor(strEnabledImage); - if (imageDescriptor != null) - { - setImageDescriptor(imageDescriptor); - } - - imageDescriptor = imageRegistry.getDescriptor(strDisabledImage); - if (imageDescriptor != null) - { - setDisabledImageDescriptor(imageDescriptor); - } - - imageDescriptor = imageRegistry.getDescriptor(strImage); - if (imageDescriptor != null) - { - setHoverImageDescriptor(imageDescriptor); - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConnectorExtension.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConnectorExtension.java new file mode 100644 index 00000000000..d73bc2b4f12 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConnectorExtension.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.RegistryFactory; + +/** + * A factory to get {@link ITerminalConnector} instances. + * + * @author Michael Scharf + * + */ +public class TerminalConnectorExtension { + /** + * @return a new list of ITerminalConnectors. + */ + public static ITerminalConnector[] getTerminalConnectors() { + IConfigurationElement[] config=RegistryFactory.getRegistry().getConfigurationElementsFor("org.eclipse.tm.terminal.terminalConnector"); //$NON-NLS-1$ + List result=new ArrayList(); + for (int i = 0; i < config.length; i++) { + try { + Object obj=config[i].createExecutableExtension("class"); //$NON-NLS-1$ + if(obj instanceof ITerminalConnector) { + ITerminalConnector conn=(ITerminalConnector) obj; + if(conn.isInstalled()) + result.add(conn); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + return (ITerminalConnector[]) result.toArray(new ITerminalConnector[result.size()]); + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConsts.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConsts.java deleted file mode 100644 index f8968d42572..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalConsts.java +++ /dev/null @@ -1,114 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -public interface TerminalConsts -{ - public static final String TERMINAL_CONNTYPE_SERIAL = "Serial"; //$NON-NLS-1$ - public static final String TERMINAL_CONNTYPE_NETWORK = "Network"; //$NON-NLS-1$ - - public final static String TERMINAL_IMAGE_DIR_ROOT = "icons/"; //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_CTOOL = "ctool16/"; // basic colors - size 16x16 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_LOCALTOOL = "clcl16/"; // basic colors - size 16x16 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_DLCL = "dlcl16/"; // disabled - size 16x16 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_ELCL = "elcl16/"; // enabled - size 16x16 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_OBJECT = "obj16/"; // basic colors - size 16x16 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_WIZBAN = "wizban/"; // basic colors - size 16x16 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_OVR = "ovr16/"; // basic colors - size 7x8 //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_VIEW = "cview16/"; // views //$NON-NLS-1$ - public final static String TERMINAL_IMAGE_DIR_EVIEW = "eview16/"; // views //$NON-NLS-1$ - - public static final String TERMINAL_IMAGE_NEW_TERMINAL = "TerminalViewNewTerminal"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_CLCL_CONNECT = "ImageClclConnect"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_CLCL_DISCONNECT = "ImageClclDisconnect"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_CLCL_SETTINGS = "ImageClclSettings"; //$NON-NLS-1$ - - public static final String TERMINAL_IMAGE_DLCL_CONNECT = "ImageDlclConnect"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_DLCL_DISCONNECT = "ImageDlclDisconnect"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_DLCL_SETTINGS = "ImageDlclSettings"; //$NON-NLS-1$ - - public static final String TERMINAL_IMAGE_ELCL_CONNECT = "ImageElclConnect"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_ELCL_DISCONNECT = "ImageElclDisconnect"; //$NON-NLS-1$ - public static final String TERMINAL_IMAGE_ELCL_SETTINGS = "ImageElclSettings"; //$NON-NLS-1$ - - public static final String TERMINAL_PROP_TITLE = Messages.getString("TerminalConsts.Terminal_7"); //$NON-NLS-1$ - public static final String TERMINAL_PROP_NAMENET = "net"; //$NON-NLS-1$ - public static final String TERMINAL_PROP_NAMETGTCONST = "tgtcons"; //$NON-NLS-1$ - public static final String TERMINAL_PROP_NAMETELNET = "telnet"; //$NON-NLS-1$ - public static final String TERMINAL_PROP_VALUENET = "1233"; //$NON-NLS-1$ - public static final String TERMINAL_PROP_VALUETGTCONST = "1232"; //$NON-NLS-1$ - public static final String TERMINAL_PROP_VALUETELNET = "23"; //$NON-NLS-1$ - - public static final String TERMINAL_PREF_LIMITOUTPUT = "TerminalPrefLimitOutput"; //$NON-NLS-1$ - public static final String TERMINAL_PREF_BUFFERLINES = "TerminalPrefBufferLines"; //$NON-NLS-1$ - public static final String TERMINAL_PREF_TIMEOUT_SERIAL = "TerminalPrefTimeoutSerial"; //$NON-NLS-1$ - public static final String TERMINAL_PREF_TIMEOUT_NETWORK = "TerminalPrefTimeoutNetwork"; //$NON-NLS-1$ - - public static final String PLUGIN_HOME = "org.eclipse.tm.terminal"; //$NON-NLS-1$ - public static final String HELP_VIEW = PLUGIN_HOME + ".terminal_view"; //$NON-NLS-1$ - - public static final String TERMINAL_TEXT_NEW_TERMINAL = Messages.getString("TerminalConsts.New_terminal"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_CONNECT = Messages.getString("TerminalConsts.Connect_2"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_DISCONNECT = Messages.getString("TerminalConsts.Disconnect_3"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_SETTINGS_ELLIPSE = Messages.getString("TerminalConsts.Settings..._4"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_COPY = Messages.getString("TerminalConsts.Copy_5"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_CUT = Messages.getString("TerminalConsts.0"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_PASTE = Messages.getString("TerminalConsts.Paste_6"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_SELECTALL = Messages.getString("TerminalConsts.Select_All_7"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_CLEARALL = Messages.getString("TerminalConsts.Clear_All_8"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_TERMINALSETTINGS = Messages.getString("TerminalConsts.Terminal_Settings_1"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_CONNECTIONTYPE = Messages.getString("TerminalConsts.Connection_Type_2"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_SETTINGS = Messages.getString("TerminalConsts.Settings_3"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_PORT = Messages.getString("TerminalConsts.Port_4"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_BAUDRATE = Messages.getString("TerminalConsts.Baud_Rate_5"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_DATABITS = Messages.getString("TerminalConsts.Data_Bits_6"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_STOPBITS = Messages.getString("TerminalConsts.Stop_Bits_7"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_PARITY = Messages.getString("TerminalConsts.Parity_8"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_FLOWCONTROL = Messages.getString("TerminalConsts.1"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_HOST = Messages.getString("TerminalConsts.Host_11"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_LIMITOUTPUT = Messages.getString("TerminalConsts.Limit_terminal_output_16"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_BUFFERLINES = Messages.getString("TerminalConsts.Terminal_buffer_lines__17"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_SERIALTIMEOUT = Messages.getString("TerminalConsts.Serial_timeout_(seconds)__18"); //$NON-NLS-1$ - public static final String TERMINAL_TEXT_NETWORKTIMEOUT = Messages.getString("TerminalConsts.Network_timeout_(seconds)__19"); //$NON-NLS-1$ - - public static final String TERMINAL_MSG_ERROR_1 = Messages.getString("TerminalConsts.Terminal_Error_12"); //$NON-NLS-1$ - public static final String TERMINAL_MSG_ERROR_2 = Messages.getString("TerminalConsts.Socket_Error_13"); //$NON-NLS-1$ - public static final String TERMINAL_MSG_ERROR_3 = Messages.getString("TerminalConsts.IO_Error_14"); //$NON-NLS-1$ - public static final String TERMINAL_MSG_ERROR_4 = Messages.getString("TerminalConsts.Serial_port___{0}___is_currently_in_use_!_nDo_you_want_to_close_the_port__15"); //$NON-NLS-1$ - public static final String TERMINAL_MSG_ERROR_5 = Messages.getString("TerminalConsts.Error_16"); //$NON-NLS-1$ - public static final String TERMINAL_MSG_ERROR_6 = Messages.getString("TerminalConsts.Emulator_is_not_supported._17"); //$NON-NLS-1$ - - public static final String TERMINAL_FONT_DEFINITION = "terminal.views.view.font.definition"; //$NON-NLS-1$ - - public static final String TERMINAL_TRACE_DEBUG_LOG = "org.eclipse.tm.terminal/debug/log"; //$NON-NLS-1$ - public static final String TERMINAL_TRACE_DEBUG_LOG_ERROR = "org.eclipse.tm.terminal/debug/log/error"; //$NON-NLS-1$ - public static final String TERMINAL_TRACE_DEBUG_LOG_INFO = "org.eclipse.tm.terminal/debug/log/info"; //$NON-NLS-1$ - public static final String TERMINAL_TRACE_DEBUG_LOG_CHAR = "org.eclipse.tm.terminal/debug/log/char"; //$NON-NLS-1$ - public static final String TERMINAL_TRACE_DEBUG_LOG_BUFFER_SIZE = "org.eclipse.tm.terminal/debug/log/buffer/size"; //$NON-NLS-1$ - - public static final boolean TERMINAL_DEFAULT_LIMITOUTPUT = true; - public static final int TERMINAL_DEFAULT_BUFFERLINES = 1000; - public static final int TERMINAL_DEFAULT_TIMEOUT_SERIAL = 5; - public static final int TERMINAL_DEFAULT_TIMEOUT_NETWORK = 5; - - public static final int TERMINAL_ID_OK = 0; - public static final int TERMINAL_ID_CANCEL = 1; - public static final int TERMINAL_ID_CONNECT = 2; - - public static final int TERMINAL_KEY_ESCAPE = 27; - public static final int TERMINAL_KEY_H = 104; - public static final int TERMINAL_KEY_J = 106; - public static final int TERMINAL_KEY_K = 107; - public static final int TERMINAL_KEY_L = 108; - public static final int TERMINAL_KEY_CR = 13; -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalCtrl.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalCtrl.java deleted file mode 100644 index 0423376d1f1..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalCtrl.java +++ /dev/null @@ -1,1573 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.net.SocketException; -import java.net.SocketTimeoutException; -import java.net.UnknownHostException; -import java.net.ConnectException; -import java.text.MessageFormat; - -import javax.comm.CommPortIdentifier; -import javax.comm.CommPortOwnershipListener; -import javax.comm.PortInUseException; -import javax.comm.SerialPort; -import javax.comm.SerialPortEvent; -import javax.comm.SerialPortEventListener; - -import org.eclipse.core.runtime.Preferences; -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.text.ConfigurableLineTracker; -import org.eclipse.jface.text.Document; -import org.eclipse.jface.text.ITextSelection; -import org.eclipse.jface.text.TextViewer; -import org.eclipse.swt.SWT; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.custom.VerifyKeyListener; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.events.KeyAdapter; -import org.eclipse.swt.events.KeyEvent; -import org.eclipse.swt.events.KeyListener; -import org.eclipse.swt.events.ModifyEvent; -import org.eclipse.swt.events.ModifyListener; -import org.eclipse.swt.events.VerifyEvent; -import org.eclipse.swt.events.VerifyListener; -import org.eclipse.swt.events.FocusEvent; -import org.eclipse.swt.events.FocusListener; -import org.eclipse.swt.graphics.Font; -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.Shell; -import org.eclipse.ui.contexts.IContextActivation; -import org.eclipse.ui.contexts.IContextService; -import org.eclipse.ui.part.ViewPart; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.keys.IBindingService; - -/** - * UNDER CONSTRUCTION - * - * 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 - */ -class TerminalCtrl implements TerminalTarget, TerminalConsts -{ - /** - * UNDER CONSTRUCTION - */ - 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. - */ - protected TerminalText m_TerminalText; - - protected Display m_Display; - protected StyledText m_ctlText; - protected TextViewer m_Viewer; - protected Composite m_wndParent; - protected CommPortIdentifier m_SerialPortIdentifier; - protected SerialPort m_SerialPort; - protected Socket m_Socket; - protected InputStream m_InputStream; - protected OutputStream m_OutputStream; - protected Clipboard m_Clipboard; - protected TerminalSerialPortHandler m_SerialPortHandler; - protected VerifyListener m_VerifyHandler; - protected TerminalModifyListener m_ModifyListener; - protected KeyListener m_KeyHandler; - protected TerminalSettings m_TerminalSettings; - protected TerminalTarget m_Target; - protected ViewPart m_ViewPart; - protected String m_strMsg = ""; //$NON-NLS-1$ - protected boolean m_bConnecting = false; - protected boolean m_bConnected = false; - protected boolean m_bOpened = false; - protected boolean m_bPortInUse = false; - protected boolean m_bCaretReset = false; - protected TelnetConnection m_telnetConnection; - protected VerifyKeyListener m_VerifyKeyListener; - protected FocusListener m_FocusListener; - - /** - * UNDER CONSTRUCTION - */ - public TerminalCtrl(TerminalTarget target, Composite wndParent) - throws Exception - { - super(); - - m_Target = target; - m_ViewPart = (ViewPart)target; - m_wndParent = wndParent; - - try - { - m_TerminalText = new TerminalText(this); - } - catch (Exception ex) - { - Logger.logException(ex); - - throw ex; - } - - setupTerminal(); - } - - /** - * UNDER CONSTRUCTION - */ - public void execute(String strMsg, Object data) - { - if (strMsg.equals(ON_TERMINAL_CONNECT)) - { - onTerminalConnect(data); - } - else if (strMsg.equals(ON_TERMINAL_CONNECTING)) - { - onTerminalConnecting(data); - } - else if (strMsg.equals(ON_TERMINAL_DISCONNECT)) - { - onTerminalDisconnect(data); - } - else if (strMsg.equals(ON_TERMINAL_STATUS)) - { - onTerminalStatus(data); - } - } - - /** - * UNDER CONSTRUCTION - */ - protected void onTerminalConnect(Object data) - { - m_Target.execute(ON_TERMINAL_CONNECT, data); - } - - /** - * UNDER CONSTRUCTION - */ - protected void onTerminalConnecting(Object data) - { - m_Target.execute(ON_TERMINAL_CONNECTING, data); - } - - /** - * UNDER CONSTRUCTION - */ - protected void onTerminalDisconnect(Object data) - { - m_Target.execute(ON_TERMINAL_DISCONNECT, data); - } - - /** - * UNDER CONSTRUCTION - */ - protected void onTerminalStatus(Object data) - { - m_Target.execute(ON_TERMINAL_STATUS, data); - } - - /** - * UNDER CONSTRUCTION - */ - public void copy() - { - m_ctlText.copy(); - } - - /** - * UNDER CONSTRUCTION - */ - public void paste() - { - TextTransfer textTransfer; - String strText; - - textTransfer = TextTransfer.getInstance(); - strText = (String)m_Clipboard.getContents(textTransfer); - - if (strText == null) - return; - - for (int i=0;i 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 - // Ctrl 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 Ctrl - // + 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 - // Ctrl-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' && - m_telnetConnection != null && - m_telnetConnection.isConnected() && - m_telnetConnection.localEcho()) - { - 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 (m_telnetConnection == null || - m_telnetConnection.isConnected() == false || - m_telnetConnection.localEcho() == 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'); - - m_TerminalText.setNewText(charBuffer); - m_Display.syncExec(m_TerminalText); - } - } - - /** - * UNDER CONSTRUCTION - */ - protected class TerminalSerialPortHandler implements SerialPortEventListener, - CommPortOwnershipListener - { - protected byte[] bytes = new byte[2048]; - - /** - * UNDER CONSTRUCTION - */ - protected TerminalSerialPortHandler() - { - super(); - } - - // Message handlers - - /** - * UNDER CONSTRUCTION - */ - protected void onSerialDataAvailable(Object data) - { - Display display; - StringBuffer buffer; - String strBuffer; - int nBytes; - - display = m_ctlText.getDisplay(); - - try - { - while (m_InputStream != null && m_InputStream.available() > 0) - { - nBytes = m_InputStream.read(bytes); - strBuffer = new String(bytes, 0, nBytes); - buffer = new StringBuffer(strBuffer); - - m_TerminalText.setNewText(buffer); - - // Do _not_ use asyncExec() here. Class TerminalText requires that - // its run() and setNewText() methods be called in strictly - // alternating order. If we were to call asyncExec() here, this - // loop might race around and call setNewText() twice in a row, - // which would lose data. - - display.syncExec(m_TerminalText); - } - } - catch (IOException ex) - { - displayTextInTerminal(ex.getMessage()); - } - catch (Exception exception) - { - Logger.logException(exception); - } - } - - /** - * UNDER CONSTRUCTION - */ - protected void onSerialOwnershipRequested(Object data) - { - TerminalSerialOwnershipRequestedWorker ownershipRequestedWorker; - Display display; - - if (m_bPortInUse) - { - m_bPortInUse = false; - return; - } - - display = m_ctlText.getDisplay(); - ownershipRequestedWorker = new TerminalSerialOwnershipRequestedWorker(); - display.asyncExec(ownershipRequestedWorker); - } - - // SerialPortEventListener interface - - /** - * UNDER CONSTRUCTION - */ - public void serialEvent(SerialPortEvent event) - { - switch (event.getEventType()) - { - case SerialPortEvent.DATA_AVAILABLE: - onSerialDataAvailable(null); - break; - } - } - - // CommPortOwnershipListener interface - - /** - * UNDER CONSTRUCTION - */ - public void ownershipChange(int nType) - { - switch (nType) - { - case CommPortOwnershipListener.PORT_OWNERSHIP_REQUESTED: - onSerialOwnershipRequested(null); - break; - } - } - } - - /** - * UNDER CONSTRUCTION - */ - protected class TerminalDocument extends Document - { - /** - * UNDER CONSTRUCTION - */ - protected TerminalDocument() - { - super(); - - setupDocument(); - } - - // Operations - - /** - * UNDER CONSTRUCTION - */ - protected void setupDocument() - { - ConfigurableLineTracker lineTracker; - - lineTracker = new ConfigurableLineTracker(LINE_DELIMITERS); - setLineTracker(lineTracker); - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalMsg.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalMsg.java deleted file mode 100644 index 158832aeb24..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalMsg.java +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -public interface TerminalMsg -{ - public static final String ON_TERMINAL_FOCUS = "OnTerminalFocus"; //$NON-NLS-1$ - public static final String ON_TERMINAL_NEW_TERMINAL = "OnTerminalNew"; //$NON-NLS-1$ - public static final String ON_TERMINAL_CONNECT = "OnTerminalConnect"; //$NON-NLS-1$ - public static final String ON_TERMINAL_CONNECTING = "OnTerminalConnecting"; //$NON-NLS-1$ - public static final String ON_TERMINAL_DISCONNECT = "OnTerminalDisconnect"; //$NON-NLS-1$ - public static final String ON_TERMINAL_SETTINGS = "OnTerminalSettings"; //$NON-NLS-1$ - public static final String ON_TERMINAL_STATUS = "OnTerminalStatus"; //$NON-NLS-1$ - public static final String ON_TERMINAL_DATAAVAILABLE = "OnTerminalDataAvailable"; //$NON-NLS-1$ - public static final String ON_TERMINAL_FONTCHANGED = "OnTerminalFontChanged"; //$NON-NLS-1$ - public static final String ON_EDIT_COPY = "OnEditCopy"; //$NON-NLS-1$ - public static final String ON_EDIT_CUT = "OnEditCut"; //$NON-NLS-1$ - public static final String ON_EDIT_PASTE = "OnEditPaste"; //$NON-NLS-1$ - public static final String ON_EDIT_CLEARALL = "OnEditClearAll"; //$NON-NLS-1$ - public static final String ON_EDIT_SELECTALL = "OnEditSelectAll"; //$NON-NLS-1$ - public static final String ON_UPDATE_TERMINAL_CONNECT = "OnUpdateTerminalConnect"; //$NON-NLS-1$ - public static final String ON_UPDATE_TERMINAL_DISCONNECT = "OnUpdateTerminalDisconnect"; //$NON-NLS-1$ - public static final String ON_UPDATE_TERMINAL_SETTINGS = "OnUpdateTerminalSettings"; //$NON-NLS-1$ - public static final String ON_UPDATE_EDIT_COPY = "OnUpdateEditCopy"; //$NON-NLS-1$ - public static final String ON_UPDATE_EDIT_CUT = "OnUpdateEditCut"; //$NON-NLS-1$ - public static final String ON_UPDATE_EDIT_PASTE = "OnUpdateEditPaste"; //$NON-NLS-1$ - public static final String ON_UPDATE_EDIT_CLEARALL = "OnUpdateEditClearAll"; //$NON-NLS-1$ - public static final String ON_UPDATE_EDIT_SELECTALL = "OnUpdateEditSelectAll"; //$NON-NLS-1$ - public static final String ON_CONNTYPE_SELECTED = "OnConnTypeSelected"; //$NON-NLS-1$ - public static final String ON_LIMITOUTPUT_SELECTED = "OnLimitOutputSelected"; //$NON-NLS-1$ - public static final String ON_OK = "OnOK"; //$NON-NLS-1$ - public static final String ON_CANCEL = "OnCancel"; //$NON-NLS-1$ - public static final String ON_HELP = "OnHelp"; //$NON-NLS-1$ -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalNetworkPortMap.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalNetworkPortMap.java deleted file mode 100644 index 47392cacf26..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalNetworkPortMap.java +++ /dev/null @@ -1,104 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Set; -import java.util.Vector; - - -public class TerminalNetworkPortMap extends HashMap - implements TerminalConsts -{ - static final long serialVersionUID = 0; - - public TerminalNetworkPortMap() - { - super(); - - setupMap(); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operations - // - - /** - * - */ - public String getDefaultNetworkPort() - { - return (String) get(TERMINAL_PROP_NAMETELNET); - } - - /** - * - */ - public String findPortName(String strPort) - { - Collection values; - Vector portTable; - Vector nameTable; - String strPortName; - int nIndex; - - values = values(); - portTable = new Vector(values); - nIndex = portTable.indexOf(strPort); - nameTable = getNameTable(); - - if (nIndex == -1) - return strPort; - - strPortName = (String) nameTable.get(nIndex); - return strPortName; - } - - /** - * - */ - public String findPort(String strPortName) - { - String strPort; - - strPort = (String) get(strPortName); - if (strPort == null) - return strPortName; - - return strPort; - } - - /** - * - */ - public Vector getNameTable() - { - Set keySet; - Vector nameTable; - - keySet = keySet(); - nameTable = new Vector(keySet); - - return nameTable; - } - - /** - * - */ - protected void setupMap() - { - put(TERMINAL_PROP_NAMETGTCONST, TERMINAL_PROP_VALUETGTCONST); - put(TERMINAL_PROP_NAMETELNET, TERMINAL_PROP_VALUETELNET); - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPlugin.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPlugin.java deleted file mode 100644 index c7489fa4032..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPlugin.java +++ /dev/null @@ -1,294 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; -import java.util.Iterator; -import java.util.MissingResourceException; -import java.util.ResourceBundle; - -import org.eclipse.core.resources.IWorkspace; -import org.eclipse.core.resources.ResourcesPlugin; -import org.eclipse.core.runtime.Platform; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.resource.ImageDescriptor; -import org.eclipse.jface.resource.ImageRegistry; -import org.eclipse.ui.plugin.AbstractUIPlugin; -import org.osgi.framework.BundleContext; - -public class TerminalPlugin extends AbstractUIPlugin - implements TerminalConsts -{ - protected static TerminalPlugin m_Default; - - protected TerminalProperties m_Properties; - protected ResourceBundle m_ResourceBundle; - - /** - * The constructor. - */ - public TerminalPlugin() - { - super(); - - m_Default = this; - - setupPlugin(); - } - - public void start(BundleContext context) throws Exception - { - super.start(context); - } - - public void stop(BundleContext context) throws Exception - { - super.stop(context); - } - - // AbstractUIPlugin interface - - /** - * - */ - protected void initializeImageRegistry(ImageRegistry imageRegistry) - { - HashMap map; - - map = new HashMap(); - - try - { - // Local toolbars - map.put(TERMINAL_IMAGE_NEW_TERMINAL, "newterminal.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_CLCL_CONNECT, "connect_co.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_CLCL_DISCONNECT, "disconnect_co.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_CLCL_SETTINGS, "properties_tsk.gif"); //$NON-NLS-1$ - - loadImageRegistry(imageRegistry, TERMINAL_IMAGE_DIR_LOCALTOOL, map); - - map.clear(); - - // Enabled local toolbars - map.put(TERMINAL_IMAGE_NEW_TERMINAL, "newterminal.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_ELCL_CONNECT, "connect_co.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_ELCL_DISCONNECT, "disconnect_co.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_ELCL_SETTINGS, "properties_tsk.gif"); //$NON-NLS-1$ - - loadImageRegistry(imageRegistry, TERMINAL_IMAGE_DIR_ELCL, map); - - map.clear(); - - // Disabled local toolbars - map.put(TERMINAL_IMAGE_NEW_TERMINAL, "newterminal.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_DLCL_CONNECT, "connect_co.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_DLCL_DISCONNECT, "disconnect_co.gif"); //$NON-NLS-1$ - map.put(TERMINAL_IMAGE_DLCL_SETTINGS, "properties_tsk.gif"); //$NON-NLS-1$ - - loadImageRegistry(imageRegistry, TERMINAL_IMAGE_DIR_DLCL, map); - - map.clear(); - } - catch(MalformedURLException malformedURLException) - { - malformedURLException.printStackTrace(); - } - } - - /** - * - */ - protected void initializeDefaultPreferences(IPreferenceStore store) - { - store.setDefault(TERMINAL_PREF_LIMITOUTPUT, TERMINAL_DEFAULT_LIMITOUTPUT); - store.setDefault(TERMINAL_PREF_BUFFERLINES, TERMINAL_DEFAULT_BUFFERLINES); - store.setDefault(TERMINAL_PREF_TIMEOUT_SERIAL, TERMINAL_DEFAULT_TIMEOUT_SERIAL); - store.setDefault(TERMINAL_PREF_TIMEOUT_NETWORK, TERMINAL_DEFAULT_TIMEOUT_NETWORK); - } - - // Operations - - /** - * Returns the shared instance. - */ - public static TerminalPlugin getDefault() - { - return m_Default; - } - - /** - * Returns the workspace instance. - */ - public static IWorkspace getWorkspace() - { - return ResourcesPlugin.getWorkspace(); - } - - /** - * Returns the string from the plugin's resource bundle, or 'key' if not found. - */ - public static String getResourceString(String strKey) - { - ResourceBundle resourceBundle; - - resourceBundle = m_Default.getResourceBundle(); - - try - { - return resourceBundle.getString(strKey); - } - catch(MissingResourceException missingResourceException) - { - return strKey; - } - } - - /** - * - */ - public static boolean isLogInfoEnabled() - { - return isOptionEnabled(TERMINAL_TRACE_DEBUG_LOG_INFO); - } - - /** - * - */ - public static boolean isLogErrorEnabled() - { - return isOptionEnabled(TERMINAL_TRACE_DEBUG_LOG_ERROR); - } - - /** - * - */ - public static boolean isLogEnabled() - { - return isOptionEnabled(TERMINAL_TRACE_DEBUG_LOG); - } - - /** - * - */ - public static boolean isOptionEnabled(String strOption) - { - String strEnabled; - Boolean boolEnabled; - boolean bEnabled; - - strEnabled = Platform.getDebugOption(strOption); - if (strEnabled == null) - return false; - - boolEnabled = new Boolean(strEnabled); - bEnabled = boolEnabled.booleanValue(); - - return bEnabled; - } - - /** - * - */ - public TerminalProperties getTerminalProperties() - { - return m_Properties; - } - - /** - * Returns the plugin's resource bundle, - */ - public ResourceBundle getResourceBundle() - { - return m_ResourceBundle; - } - - /** - * - */ - protected void loadImageRegistry(ImageRegistry imageRegistry, - String strDir, - HashMap map) - throws MalformedURLException - { - URL url; - ImageDescriptor imageDescriptor; - Iterator keys; - String strKey; - String strFile; - - keys = map.keySet().iterator(); - - while(keys.hasNext()) - { - strKey = (String) keys.next(); - strFile = (String) map.get(strKey); - - if (strFile != null) - { - url = TerminalPlugin.getDefault().getBundle().getEntry(TERMINAL_IMAGE_DIR_ROOT + strDir + strFile); - imageDescriptor = ImageDescriptor.createFromURL(url); - imageRegistry.put(strKey,imageDescriptor); - } - } - } - - /** - * - */ - protected void setupPlugin() - { - setupData(); - setupLog(); - setupResources(); - } - - /** - * - */ - protected void setupData() - { - m_Properties = new TerminalProperties(); - } - - /** - * - */ - protected void setupLog() - { - } - - /** - * - */ - protected void setupResources() - { - Package pkg; - String strPkg; - String strBundle; - - pkg = TerminalPlugin.class.getPackage(); - strPkg = pkg.getName(); - strBundle = strPkg + ".PluginResources"; //$NON-NLS-1$ - - try - { - m_ResourceBundle = ResourceBundle.getBundle(strBundle); - } - catch(MissingResourceException missingResourceException) - { - m_ResourceBundle = null; - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPreferencePage.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPreferencePage.java deleted file mode 100644 index 4071b47f6d5..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalPreferencePage.java +++ /dev/null @@ -1,265 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import org.eclipse.jface.preference.BooleanFieldEditor; -import org.eclipse.jface.preference.FieldEditorPreferencePage; -import org.eclipse.jface.preference.IPreferenceStore; -import org.eclipse.jface.preference.IntegerFieldEditor; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.widgets.Button; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Text; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchPreferencePage; - -public class TerminalPreferencePage extends FieldEditorPreferencePage - implements IWorkbenchPreferencePage, - TerminalTarget, - TerminalConsts -{ - /** - * - */ - protected TerminalBooleanFieldEditor m_editorLimitOutput; - protected IntegerFieldEditor m_editorBufferSize; - protected IntegerFieldEditor m_editorSerialTimeout; - protected IntegerFieldEditor m_editorNetworkTimeout; - - /** - * - */ - public TerminalPreferencePage() - { - super(GRID); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // TerminalTarget interface - // - - /** - * - */ - public void execute(String strMsg,Object data) - { - if (strMsg.equals(ON_LIMITOUTPUT_SELECTED)) - { - onLimitOutputSelected(data); - } - else - { - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Message handlers - // - - /** - * - */ - protected void onLimitOutputSelected(Object data) - { - Button ctlButton; - Text ctlText; - Label ctlLabel; - boolean bEnabled; - - ctlButton = m_editorLimitOutput.getChangeControl(getFieldEditorParent()); - ctlText = m_editorBufferSize.getTextControl(getFieldEditorParent()); - ctlLabel = m_editorBufferSize.getLabelControl(getFieldEditorParent()); - bEnabled = ctlButton.getSelection(); - - ctlText.setEnabled(bEnabled); - ctlLabel.setEnabled(bEnabled); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // FieldEditorPreferencePage interface - // - - /** - * - */ - protected void createFieldEditors() - { - setupPage(); - } - - /** - * - */ - protected void initialize() - { - super.initialize(); - - execute(ON_LIMITOUTPUT_SELECTED,null); - } - - /** - * - */ - protected void performDefaults() - { - super.performDefaults(); - - execute(ON_LIMITOUTPUT_SELECTED,null); - } - - /** - * - */ - public void init(IWorkbench workbench) - { - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operations - // - - /** - * - */ - protected void setupPage() - { - setupData(); - setupEditors(); - setupListeners(); - } - - /** - * - */ - protected void setupData() - { - TerminalPlugin plugin; - IPreferenceStore preferenceStore; - - plugin = TerminalPlugin.getDefault(); - preferenceStore = plugin.getPreferenceStore(); - setPreferenceStore(preferenceStore); - } - - /** - * - */ - protected void setupEditors() - { - m_editorLimitOutput = new TerminalBooleanFieldEditor(TERMINAL_PREF_LIMITOUTPUT, - TERMINAL_TEXT_LIMITOUTPUT, - getFieldEditorParent()); - m_editorBufferSize = new IntegerFieldEditor(TERMINAL_PREF_BUFFERLINES, - TERMINAL_TEXT_BUFFERLINES, - getFieldEditorParent()); - m_editorSerialTimeout = new IntegerFieldEditor(TERMINAL_PREF_TIMEOUT_SERIAL, - TERMINAL_TEXT_SERIALTIMEOUT, - getFieldEditorParent()); - m_editorNetworkTimeout = new IntegerFieldEditor(TERMINAL_PREF_TIMEOUT_NETWORK, - TERMINAL_TEXT_NETWORKTIMEOUT, - getFieldEditorParent()); - - m_editorBufferSize.setValidRange(0,Integer.MAX_VALUE); - m_editorSerialTimeout.setValidRange(0,Integer.MAX_VALUE); - m_editorNetworkTimeout.setValidRange(0,Integer.MAX_VALUE); - - addField(m_editorLimitOutput); - addField(m_editorBufferSize); - addField(m_editorSerialTimeout); - addField(m_editorNetworkTimeout); - } - - /** - * - */ - protected void setupListeners() - { - TerminalSelectionHandler selectionHandler; - Button ctlButton; - - selectionHandler = new TerminalSelectionHandler(); - ctlButton = m_editorLimitOutput.getChangeControl(getFieldEditorParent()); - ctlButton.addSelectionListener(selectionHandler); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Inner classes - // - - /** - * - */ - public class TerminalBooleanFieldEditor extends BooleanFieldEditor - { - /** - * - */ - public TerminalBooleanFieldEditor(String strName, - String strLabel, - Composite ctlParent) - { - super(strName,strLabel,ctlParent); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // BooleanFieldEditor interface - // - - /** - * - */ - public Button getChangeControl(Composite parent) - { - return super.getChangeControl(parent); - } - } - - - /** - * - */ - protected class TerminalSelectionHandler extends SelectionAdapter - { - /** - * - */ - protected TerminalSelectionHandler() - { - super(); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // SelectionAdapter interface - // - - /** - * - */ - public void widgetSelected(SelectionEvent event) - { - Object source; - Button ctlButton; - - source = event.getSource(); - ctlButton = m_editorLimitOutput.getChangeControl(getFieldEditorParent()); - - if (source == ctlButton) - { - execute(ON_LIMITOUTPUT_SELECTED,null); - } - } - - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalProperties.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalProperties.java deleted file mode 100644 index 54435d95ff0..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalProperties.java +++ /dev/null @@ -1,278 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.Vector; - -import javax.comm.CommPortIdentifier; - -public class TerminalProperties implements TerminalConsts -{ - protected TerminalNetworkPortMap m_NetworkPortMap; - protected Vector m_ConnTypeTable; - protected Vector m_SerialPortTable; - protected Vector m_BaudRateTable; - protected Vector m_DataBitsTable; - protected Vector m_StopBitsTable; - protected Vector m_ParityTable; - protected Vector m_FlowControlTable; - protected String m_strDefaultConnType; - protected String m_strDefaultSerialPort; - protected String m_strDefaultBaudRate; - protected String m_strDefaultDataBits; - protected String m_strDefaultStopBits; - protected String m_strDefaultParity; - protected String m_strDefaultFlowControl; - protected String m_strDefaultHost; - protected String m_strDefaultNetworkPort; - - /** - * - */ - public TerminalProperties() - { - super(); - - setupProperties(); - } - - //////////////////////////////////////////////////////////////////////////// - // Operations - // - - /** - * - */ - public Vector getConnTypeTable() - { - return m_ConnTypeTable; - } - - /** - * - */ - public Vector getSerialPortTable() - { - return m_SerialPortTable; - } - - /** - * - */ - public Vector getBaudRateTable() - { - return m_BaudRateTable; - } - - /** - * - */ - public Vector getDataBitsTable() - { - return m_DataBitsTable; - } - - /** - * - */ - public Vector getStopBitsTable() - { - return m_StopBitsTable; - } - - /** - * - */ - public Vector getParityTable() - { - return m_ParityTable; - } - - /** - * - */ - public Vector getFlowControlTable() - { - return m_FlowControlTable; - } - - /** - * - */ - public TerminalNetworkPortMap getNetworkPortMap() - { - return m_NetworkPortMap; - } - - /** - * - */ - public String getDefaultConnType() - { - return m_strDefaultConnType; - } - - /** - * - */ - public String getDefaultSerialPort() - { - return m_strDefaultSerialPort; - } - - /** - * - */ - public String getDefaultBaudRate() - { - return m_strDefaultBaudRate; - } - - /** - * - */ - public String getDefaultDataBits() - { - return m_strDefaultDataBits; - } - - /** - * - */ - public String getDefaultStopBits() - { - return m_strDefaultStopBits; - } - - /** - * - */ - public String getDefaultParity() - { - return m_strDefaultParity; - } - - /** - * - */ - public String getDefaultFlowControl() - { - return m_strDefaultFlowControl; - } - - /** - * - */ - public String getDefaultHost() - { - return m_strDefaultHost; - } - - /** - * - */ - public String getDefaultNetworkPort() - { - return m_strDefaultNetworkPort; - } - - /** - * - */ - protected void setupProperties() - { - Enumeration portIdEnum; - CommPortIdentifier identifier; - String strName; - int nPortType; - - portIdEnum = CommPortIdentifier.getPortIdentifiers(); - m_NetworkPortMap = new TerminalNetworkPortMap(); - m_ConnTypeTable = new Vector(); - m_SerialPortTable = new Vector(); - m_BaudRateTable = new Vector(); - m_DataBitsTable = new Vector(); - m_StopBitsTable = new Vector(); - m_ParityTable = new Vector(); - m_FlowControlTable = new Vector(); - m_strDefaultConnType = ""; //$NON-NLS-1$ - m_strDefaultSerialPort = ""; //$NON-NLS-1$ - m_strDefaultBaudRate = ""; //$NON-NLS-1$ - m_strDefaultDataBits = ""; //$NON-NLS-1$ - m_strDefaultStopBits = ""; //$NON-NLS-1$ - m_strDefaultParity = ""; //$NON-NLS-1$ - m_strDefaultFlowControl = ""; //$NON-NLS-1$ - m_strDefaultHost = ""; //$NON-NLS-1$ - m_strDefaultNetworkPort = ""; //$NON-NLS-1$ - - m_ConnTypeTable.add(TERMINAL_CONNTYPE_SERIAL); - m_ConnTypeTable.add(TERMINAL_CONNTYPE_NETWORK); - - m_BaudRateTable.add("300"); //$NON-NLS-1$ - m_BaudRateTable.add("1200"); //$NON-NLS-1$ - m_BaudRateTable.add("2400"); //$NON-NLS-1$ - m_BaudRateTable.add("4800"); //$NON-NLS-1$ - m_BaudRateTable.add("9600"); //$NON-NLS-1$ - m_BaudRateTable.add("19200"); //$NON-NLS-1$ - m_BaudRateTable.add("38400"); //$NON-NLS-1$ - m_BaudRateTable.add("57600"); //$NON-NLS-1$ - m_BaudRateTable.add("115200"); //$NON-NLS-1$ - - m_DataBitsTable.add("5"); //$NON-NLS-1$ - m_DataBitsTable.add("6"); //$NON-NLS-1$ - m_DataBitsTable.add("7"); //$NON-NLS-1$ - m_DataBitsTable.add("8"); //$NON-NLS-1$ - - m_StopBitsTable.add("1"); //$NON-NLS-1$ - m_StopBitsTable.add("1_5"); //$NON-NLS-1$ - m_StopBitsTable.add("2"); //$NON-NLS-1$ - - m_ParityTable.add("None"); //$NON-NLS-1$ - m_ParityTable.add("Even"); //$NON-NLS-1$ - m_ParityTable.add("Odd"); //$NON-NLS-1$ - m_ParityTable.add("Mark"); //$NON-NLS-1$ - m_ParityTable.add("Space"); //$NON-NLS-1$ - - m_FlowControlTable.add("None"); //$NON-NLS-1$ - m_FlowControlTable.add("RTS/CTS"); //$NON-NLS-1$ - m_FlowControlTable.add("Xon/Xoff"); //$NON-NLS-1$ - - m_strDefaultNetworkPort = m_NetworkPortMap.getDefaultNetworkPort(); - m_strDefaultConnType = (String) m_ConnTypeTable.get(0); - m_strDefaultBaudRate = (String) m_BaudRateTable.get(4); - m_strDefaultDataBits = (String) m_DataBitsTable.get(3); - m_strDefaultStopBits = (String) m_StopBitsTable.get(0); - m_strDefaultParity = (String) m_ParityTable.get(0); - m_strDefaultFlowControl = (String) m_FlowControlTable.get(0); - m_strDefaultHost = ""; //$NON-NLS-1$ - - while(portIdEnum.hasMoreElements()) - { - identifier = (CommPortIdentifier)portIdEnum.nextElement(); - strName = identifier.getName(); - nPortType = identifier.getPortType(); - - if (nPortType == CommPortIdentifier.PORT_SERIAL) - m_SerialPortTable.addElement(strName); - } - - Collections.sort(m_SerialPortTable); - - if (!m_SerialPortTable.isEmpty()) - { - m_strDefaultSerialPort = (String) m_SerialPortTable.get(0); - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettings.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettings.java deleted file mode 100644 index 516ec202843..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettings.java +++ /dev/null @@ -1,425 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import javax.comm.SerialPort; - -import org.eclipse.jface.dialogs.IDialogSettings; - -public class TerminalSettings - implements TerminalConsts -{ - protected String m_strConnType; - protected String m_strSerialPort; - protected String m_strBaudRate; - protected String m_strDataBits; - protected String m_strStopBits; - protected String m_strParity; - protected String m_strFlowControl; - protected String m_strHost; - protected String m_strNetworkPort; - - /** - * - */ - public TerminalSettings(String terminalPartName) - { - importSettings(terminalPartName); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operations - // - - /** - * - */ - public String getConnType() - { - return m_strConnType; - } - - /** - * - */ - public void setConnType(String strConnType) - { - m_strConnType = strConnType; - } - - /** - * - */ - public String getSerialPort() - { - return m_strSerialPort; - } - - /** - * - */ - public void setSerialPort(String strSerialPort) - { - m_strSerialPort = strSerialPort; - } - - /** - * - */ - public String getBaudRate() - { - return m_strBaudRate; - } - - /** - * - */ - public int getBaudRateValue() - { - int nBaudRate; - - try - { - nBaudRate = Integer.parseInt(m_strBaudRate); - } - catch(NumberFormatException numberFormatException) - { - nBaudRate = 9600; - } - - return nBaudRate; - } - - /** - * - */ - public void setBaudRate(String strBaudRate) - { - m_strBaudRate = strBaudRate; - } - - /** - * - */ - public String getDataBits() - { - return m_strDataBits; - } - - /** - * - */ - public int getDataBitsValue() - { - if (m_strDataBits.equals("5")) //$NON-NLS-1$ - { - return SerialPort.DATABITS_5; - } - else if (m_strDataBits.equals("6")) //$NON-NLS-1$ - { - return SerialPort.DATABITS_6; - } - else if (m_strDataBits.equals("7")) //$NON-NLS-1$ - { - return SerialPort.DATABITS_7; - } - else // 8 - { - return SerialPort.DATABITS_8; - } - } - - /** - * - */ - public void setDataBits(String strDataBits) - { - m_strDataBits = strDataBits; - } - - /** - * - */ - public String getStopBits() - { - return m_strStopBits; - } - - /** - * - */ - public int getStopBitsValue() - { - if (m_strStopBits.equals("1_5")) //$NON-NLS-1$ - { - return SerialPort.STOPBITS_1_5; - } - else if (m_strStopBits.equals("2")) //$NON-NLS-1$ - { - return SerialPort.STOPBITS_2; - } - else // 1 - { - return SerialPort.STOPBITS_1; - } - } - - /** - * - */ - public void setStopBits(String strStopBits) - { - m_strStopBits = strStopBits; - } - - /** - * - */ - public String getParity() - { - return m_strParity; - } - - /** - * - */ - public int getParityValue() - { - if (m_strParity.equals("Even")) //$NON-NLS-1$ - { - return SerialPort.PARITY_EVEN; - } - else if (m_strParity.equals("Odd")) //$NON-NLS-1$ - { - return SerialPort.PARITY_ODD; - } - else if (m_strParity.equals("Mark")) //$NON-NLS-1$ - { - return SerialPort.PARITY_MARK; - } - else if (m_strParity.equals("Space")) //$NON-NLS-1$ - { - return SerialPort.PARITY_SPACE; - } - else // None - { - return SerialPort.PARITY_NONE; - } - } - - /** - * - */ - public void setParity(String strParity) - { - m_strParity = strParity; - } - - /** - * - */ - public String getFlowControl() - { - return m_strFlowControl; - } - - /** - * - */ - public int getFlowControlValue() - { - if (m_strFlowControl.equals("RTS/CTS")) //$NON-NLS-1$ - { - return SerialPort.FLOWCONTROL_RTSCTS_IN; - } - else if (m_strFlowControl.equals("Xon/Xoff")) //$NON-NLS-1$ - { - return SerialPort.FLOWCONTROL_XONXOFF_IN; - } - else // None - { - return SerialPort.FLOWCONTROL_NONE; - } - } - - /** - * - */ - public void setFlowControl(String strFlow) - { - m_strFlowControl = strFlow; - } - - /** - * - */ - public String getHost() - { - return m_strHost; - } - - /** - * - */ - public void setHost(String strHost) - { - m_strHost = strHost; - } - - /** - * - */ - public String getNetworkPort() - { - return m_strNetworkPort; - } - - /** - * - */ - public int getNetworkPortValue() - { - int nNetworkPort; - - try - { - nNetworkPort = Integer.parseInt(m_strNetworkPort); - } - catch(NumberFormatException numberFormatException) - { - nNetworkPort = 1313; - } - - return nNetworkPort; - } - - /** - * - */ - public void setNetworkPort(String strNetworkPort) - { - m_strNetworkPort = strNetworkPort; - } - - /** - * - */ - public void importSettings(String terminalPartName) - { - TerminalPlugin plugin; - TerminalProperties properties; - - plugin = TerminalPlugin.getDefault(); - properties = plugin.getTerminalProperties(); - m_strConnType = importSetting(terminalPartName, "ConnType", //$NON-NLS-1$ - properties.getDefaultConnType()); - m_strSerialPort = importSetting(terminalPartName, "SerialPort", //$NON-NLS-1$ - properties.getDefaultSerialPort()); - m_strBaudRate = importSetting(terminalPartName, "BaudRate", //$NON-NLS-1$ - properties.getDefaultBaudRate()); - m_strDataBits = importSetting(terminalPartName, "DataBits", //$NON-NLS-1$ - properties.getDefaultDataBits()); - m_strStopBits = importSetting(terminalPartName, "StopBits", //$NON-NLS-1$ - properties.getDefaultStopBits()); - m_strParity = importSetting(terminalPartName, "Parity", //$NON-NLS-1$ - properties.getDefaultParity()); - m_strFlowControl = importSetting(terminalPartName, "FlowControl", //$NON-NLS-1$ - properties.getDefaultFlowControl()); - m_strHost = importSetting(terminalPartName, "Host", //$NON-NLS-1$ - properties.getDefaultHost()); - m_strNetworkPort = importSetting(terminalPartName, "NetworkPort", //$NON-NLS-1$ - properties.getDefaultNetworkPort()); - } - - /** - * - */ - public void exportSettings(String terminalPartName) - { - TerminalPlugin plugin; - TerminalProperties properties; - - plugin = TerminalPlugin.getDefault(); - properties = plugin.getTerminalProperties(); - - exportSetting(terminalPartName, "ConnType", m_strConnType, //$NON-NLS-1$ - properties.getDefaultConnType()); - exportSetting(terminalPartName, "SerialPort", m_strSerialPort, //$NON-NLS-1$ - properties.getDefaultSerialPort()); - exportSetting(terminalPartName, "BaudRate", m_strBaudRate, //$NON-NLS-1$ - properties.getDefaultBaudRate()); - exportSetting(terminalPartName, "DataBits", m_strDataBits, //$NON-NLS-1$ - properties.getDefaultDataBits()); - exportSetting(terminalPartName, "StopBits", m_strStopBits, //$NON-NLS-1$ - properties.getDefaultStopBits()); - exportSetting(terminalPartName, "Parity", m_strParity, //$NON-NLS-1$ - properties.getDefaultParity()); - exportSetting(terminalPartName, "FlowControl", m_strFlowControl, //$NON-NLS-1$ - properties.getDefaultFlowControl()); - exportSetting(terminalPartName, "Host", m_strHost, //$NON-NLS-1$ - properties.getDefaultHost()); - exportSetting(terminalPartName, "NetworkPort", m_strNetworkPort, //$NON-NLS-1$ - properties.getDefaultNetworkPort()); - } - - /** - * - */ - protected String importSetting(String terminalPartName, String strName, String strDefault) - { - TerminalPlugin plugin; - IDialogSettings settings; - String strPrefix; - String strKey; - String strValue; - - plugin = TerminalPlugin.getDefault(); - settings = plugin.getDialogSettings(); - strPrefix = TerminalSettings.class.getName() + "."; //$NON-NLS-1$ - strKey = strPrefix + terminalPartName + "." + strName; //$NON-NLS-1$ - strValue = settings.get(strKey); - - if ((strValue == null) || - (strValue.equals(""))) //$NON-NLS-1$ - return strDefault; - - return strValue; - } - - /** - * - */ - protected void exportSetting(String terminalPartName, String strName, String strValue, - String strDefault) - { - TerminalPlugin plugin; - IDialogSettings settings; - String strPrefix; - String strKey; - - plugin = TerminalPlugin.getDefault(); - settings = plugin.getDialogSettings(); - strPrefix = TerminalSettings.class.getName() + "."; //$NON-NLS-1$ - strKey = strPrefix + terminalPartName + "." + strName; //$NON-NLS-1$ - - if ((strValue == null) || - (strValue.equals(""))) //$NON-NLS-1$ - { - settings.put(strKey,strDefault); - } - else - { - settings.put(strKey,strValue); - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettingsDlg.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettingsDlg.java deleted file mode 100644 index 88d00c2ea9e..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalSettingsDlg.java +++ /dev/null @@ -1,911 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import java.util.Collections; -import java.util.Enumeration; -import java.util.Vector; - -import javax.comm.CommPortIdentifier; - -import org.eclipse.jface.dialogs.MessageDialog; -import org.eclipse.swt.SWT; -import org.eclipse.swt.events.SelectionAdapter; -import org.eclipse.swt.events.SelectionEvent; -import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.layout.GridData; -import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Control; -import org.eclipse.swt.widgets.Group; -import org.eclipse.swt.widgets.Label; -import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Text; - - -public class TerminalSettingsDlg extends org.eclipse.jface.dialogs.Dialog - implements TerminalTarget, - TerminalConsts -{ - protected static final String m_strHelpID = "hid_db_terminal"; //$NON-NLS-1$ - - protected Combo m_ctlConnTypeCombo; - protected Combo m_ctlSerialPortCombo; - protected Combo m_ctlBaudRateCombo; - protected Combo m_ctlDataBitsCombo; - protected Combo m_ctlStopBitsCombo; - protected Combo m_ctlParityCombo; - protected Combo m_ctlFlowControlCombo; - protected Text m_ctlHostText; - protected Combo m_ctlNetworkPortCombo; - protected Group m_wndSettingsGroup; - protected Composite m_wndSettingsPanel; - protected TerminalSettings m_TerminalSettings; - protected String m_strConnType; - protected int m_nStatus; - - /** - * - */ - public TerminalSettingsDlg(Shell wndParent) - { - super(wndParent); - - m_nStatus = TERMINAL_ID_CANCEL; - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // TerminalTarget interface - // - - /** - * - */ - public void execute(String strMsg,Object data) - { - if (strMsg.equals(ON_CONNTYPE_SELECTED)) - { - onConnTypeSelected(data); - } - else if (strMsg.equals(ON_OK)) - { - onOk(data); - } - else if (strMsg.equals(ON_CANCEL)) - { - onCancel(data); - } - else if (strMsg.equals(ON_HELP)) - { - onHelp(data); - } - else - { - } - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Message handlers - // - - /** - * - */ - protected void onConnTypeSelected(Object data) - { - String strConnType; - - strConnType = m_ctlConnTypeCombo.getText(); - if (m_strConnType.equals(strConnType)) - return; - - m_strConnType = strConnType; - - if (strConnType.equals(TERMINAL_CONNTYPE_SERIAL)) - { - setupSerialPanel(); - } - else if (strConnType.equals(TERMINAL_CONNTYPE_NETWORK)) - { - setupNetworkPanel(); - } - else - { - setupConnTypeNotSupportedPanel(); - } - } - - /** - * - */ - protected void onOk(Object data) - { - if (!validateSettings()) - return; - - saveSettings(); - m_nStatus = TERMINAL_ID_CONNECT; - } - - /** - * - */ - protected void onCancel(Object data) - { - m_nStatus = TERMINAL_ID_CANCEL; - } - - /** - * - */ - protected void onHelp(Object data) - { - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Dialog interface - // - - /** - * - */ - protected void okPressed() - { - execute(ON_OK,null); - super.okPressed(); - } - - /** - * - */ - protected void cancelPressed() - { - execute(ON_CANCEL,null); - super.cancelPressed(); - - } - - /** - * - */ - public int open() - { - int nShellStyle; - - nShellStyle = getShellStyle(); - nShellStyle = nShellStyle|SWT.RESIZE; - setShellStyle(nShellStyle); - - return super.open(); - } - - /** - * - */ - protected void configureShell(Shell newShell) - { - super.configureShell(newShell); - - newShell.setText(TERMINAL_TEXT_TERMINALSETTINGS); - } - - /** - * - */ - protected Control createDialogArea(Composite parent) - { - Composite ctlComposite; - - ctlComposite = (Composite)super.createDialogArea(parent); - createDialog(ctlComposite); - - return ctlComposite; - } - - /** - * - */ - protected void initializeBounds() - { - setConnType(TERMINAL_CONNTYPE_SERIAL); - execute(ON_CONNTYPE_SELECTED,null); - super.initializeBounds(); - setConnType(m_TerminalSettings.getConnType()); - execute(ON_CONNTYPE_SELECTED,null); - } - - //////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - // Operations - // - - /** - * - */ - public void loadSettings(TerminalSettings terminalSettings) - { - m_TerminalSettings = terminalSettings; - } - - /** - * - */ - public void saveSettings() - { - String strConnType; - - strConnType = getConnType(); - - if (strConnType.equals(TERMINAL_CONNTYPE_SERIAL)) - { - m_TerminalSettings.setConnType(getConnType()); - m_TerminalSettings.setSerialPort(getSerialPort()); - m_TerminalSettings.setBaudRate(getBaudRate()); - m_TerminalSettings.setDataBits(getDataBits()); - m_TerminalSettings.setStopBits(getStopBits()); - m_TerminalSettings.setParity(getParity()); - m_TerminalSettings.setFlowControl(getFlowControl()); - } - else if (strConnType.equals(TERMINAL_CONNTYPE_NETWORK)) - { - m_TerminalSettings.setConnType(getConnType()); - m_TerminalSettings.setHost(getHost()); - m_TerminalSettings.setNetworkPort(getNetworkPort()); - } - } - - /** - * - */ - public int getStatus() - { - return m_nStatus; - } - - /** - * - */ - protected void setConnType(String strConnType) - { - int nIndex; - - nIndex = m_ctlConnTypeCombo.indexOf(strConnType); - if (nIndex == -1) - return; - - m_ctlConnTypeCombo.select(nIndex); - } - - /** - * - */ - protected void setSerialPort(String strSerialPort) - { - int nIndex; - - nIndex = m_ctlSerialPortCombo.indexOf(strSerialPort); - if (nIndex == -1) - return; - - m_ctlSerialPortCombo.select(nIndex); - } - - /** - * - */ - protected void setBaudRate(String strBaudRate) - { - int nIndex; - - nIndex = m_ctlBaudRateCombo.indexOf(strBaudRate); - if (nIndex == -1) - return; - - m_ctlBaudRateCombo.select(nIndex); - } - - /** - * - */ - protected void setDataBits(String strDataBits) - { - int nIndex; - - nIndex = m_ctlDataBitsCombo.indexOf(strDataBits); - if (nIndex == -1) - return; - - m_ctlDataBitsCombo.select(nIndex); - } - - /** - * - */ - protected void setStopBits(String strStopBits) - { - int nIndex; - - nIndex = m_ctlStopBitsCombo.indexOf(strStopBits); - if (nIndex == -1) - return; - - m_ctlStopBitsCombo.select(nIndex); - } - - /** - * - */ - protected void setParity(String strParity) - { - int nIndex; - - nIndex = m_ctlParityCombo.indexOf(strParity); - if (nIndex == -1) - return; - - m_ctlParityCombo.select(nIndex); - } - - /** - * - */ - protected void setFlowIn(String strFlowIn) - { - int nIndex; - - nIndex = m_ctlFlowControlCombo.indexOf(strFlowIn); - if (nIndex == -1) - return; - - m_ctlFlowControlCombo.select(nIndex); - } - - /** - * - */ - protected void setHost(String strHost) - { - m_ctlHostText.setText(strHost); - } - - /** - * - */ - protected void setNetworkPort(String strNetworkPort) - { - TerminalPlugin plugin; - TerminalProperties properties; - TerminalNetworkPortMap networkPortMap; - String strPortName; - int nIndex; - - plugin = TerminalPlugin.getDefault(); - properties = plugin.getTerminalProperties(); - networkPortMap = properties.getNetworkPortMap(); - strPortName = networkPortMap.findPortName(strNetworkPort); - nIndex = m_ctlNetworkPortCombo.indexOf(strPortName); - - if (nIndex == -1) - { - m_ctlNetworkPortCombo.setText(strNetworkPort); - } - else - { - m_ctlNetworkPortCombo.select(nIndex); - } - } - - /** - * - */ - protected String getConnType() - { - int nIndex; - - nIndex = m_ctlConnTypeCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlConnTypeCombo.getItem(nIndex); - } - - /** - * - */ - protected String getSerialPort() - { - int nIndex; - - nIndex = m_ctlSerialPortCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlSerialPortCombo.getItem(nIndex); - } - - /** - * - */ - protected String getBaudRate() - { - int nIndex; - - nIndex = m_ctlBaudRateCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlBaudRateCombo.getItem(nIndex); - } - - /** - * - */ - protected String getDataBits() - { - int nIndex; - - nIndex = m_ctlDataBitsCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlDataBitsCombo.getItem(nIndex); - } - - /** - * - */ - protected String getStopBits() - { - int nIndex; - - nIndex = m_ctlStopBitsCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlStopBitsCombo.getItem(nIndex); - } - - /** - * - */ - protected String getParity() - { - int nIndex; - - nIndex = m_ctlParityCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlParityCombo.getItem(nIndex); - } - - /** - * - */ - protected String getFlowControl() - { - int nIndex; - - nIndex = m_ctlFlowControlCombo.getSelectionIndex(); - if (nIndex == -1) - return ""; //$NON-NLS-1$ - - return m_ctlFlowControlCombo.getItem(nIndex); - } - - /** - * - */ - protected String getHost() - { - return m_ctlHostText.getText(); - } - - /** - * - */ - protected String getNetworkPort() - { - TerminalPlugin plugin; - TerminalProperties properties; - TerminalNetworkPortMap networkPortMap; - String strPortName; - String strPort; - - plugin = TerminalPlugin.getDefault(); - properties = plugin.getTerminalProperties(); - networkPortMap = properties.getNetworkPortMap(); - strPortName = m_ctlNetworkPortCombo.getText(); - strPort = networkPortMap.findPort(strPortName); - - return strPort; - } - - /** - * - */ - protected boolean validateSettings() - { - return true; - } - - /** - * - */ - protected void createDialog(Composite ctlComposite) - { - setupData(); - setupPanel(ctlComposite); - setupListeners(); - } - - /** - * - */ - protected void setupData() - { - m_strConnType = ""; //$NON-NLS-1$ - } - - /** - * - */ - protected void setupPanel(Composite wndParent) - { - setupConnTypePanel(wndParent); - setupSettingsGroup(wndParent); - } - - /** - * - */ - protected void setupConnTypePanel(Composite wndParent) - { - Group wndGroup; - GridLayout gridLayout; - GridData gridData; - - wndGroup = new Group(wndParent,SWT.NONE); - gridLayout = new GridLayout(1,true); - gridData = new GridData(GridData.FILL_HORIZONTAL); - - wndGroup.setLayout(gridLayout); - wndGroup.setLayoutData(gridData); - wndGroup.setText(TERMINAL_TEXT_CONNECTIONTYPE + ":"); //$NON-NLS-1$ - - m_ctlConnTypeCombo = new Combo(wndGroup,SWT.DROP_DOWN|SWT.READ_ONLY); - gridData = new GridData(GridData.FILL_HORIZONTAL); - gridData.widthHint = 200; - m_ctlConnTypeCombo.setLayoutData(gridData); - - // Load controls - m_ctlConnTypeCombo.add(TERMINAL_CONNTYPE_SERIAL); - m_ctlConnTypeCombo.add(TERMINAL_CONNTYPE_NETWORK); - } - - /** - * - */ - protected void setupSettingsGroup(Composite parent) - { - m_wndSettingsGroup = new Group(parent,SWT.NONE); - GridLayout gridLayout = new GridLayout(); - GridData gridData = new GridData(GridData.FILL_BOTH); - - m_wndSettingsGroup.setText(TERMINAL_TEXT_SETTINGS + ":"); //$NON-NLS-1$ - m_wndSettingsGroup.setLayout(gridLayout); - m_wndSettingsGroup.setLayoutData(gridData); - } - - /** - * - */ - protected void setupSerialPanel() - { - TerminalPlugin plugin; - TerminalProperties properties; - Label ctlLabel; - GridLayout gridLayout; - GridData gridData; - Vector table; - - if (m_wndSettingsPanel != null) - { - m_wndSettingsPanel.setVisible(false); - m_wndSettingsPanel.dispose(); - } - - plugin = TerminalPlugin.getDefault(); - properties = plugin.getTerminalProperties(); - m_wndSettingsPanel = new Composite(m_wndSettingsGroup,SWT.NONE); - gridLayout = new GridLayout(2,false); - gridData = new GridData(GridData.FILL_HORIZONTAL); - - m_wndSettingsPanel.setLayout(gridLayout); - m_wndSettingsPanel.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_PORT + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlSerialPortCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN|SWT.READ_ONLY); - m_ctlSerialPortCombo.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_BAUDRATE + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlBaudRateCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN|SWT.READ_ONLY); - m_ctlBaudRateCombo.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_DATABITS + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlDataBitsCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN|SWT.READ_ONLY); - m_ctlDataBitsCombo.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_STOPBITS + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlStopBitsCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN|SWT.READ_ONLY); - m_ctlStopBitsCombo.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_PARITY + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlParityCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN|SWT.READ_ONLY); - m_ctlParityCombo.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_FLOWCONTROL + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlFlowControlCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN|SWT.READ_ONLY); - m_ctlFlowControlCombo.setLayoutData(gridData); - - // Load controls - table = properties.getSerialPortTable(); - loadCombo(m_ctlSerialPortCombo,table); - - table = properties.getBaudRateTable(); - loadCombo(m_ctlBaudRateCombo,table); - - table = properties.getDataBitsTable(); - loadCombo(m_ctlDataBitsCombo,table); - - table = properties.getStopBitsTable(); - loadCombo(m_ctlStopBitsCombo,table); - - table = properties.getParityTable(); - loadCombo(m_ctlParityCombo,table); - - table = properties.getFlowControlTable(); - loadCombo(m_ctlFlowControlCombo,table); - - setSerialPort(m_TerminalSettings.getSerialPort()); - setBaudRate(m_TerminalSettings.getBaudRate()); - setDataBits(m_TerminalSettings.getDataBits()); - setStopBits(m_TerminalSettings.getStopBits()); - setParity(m_TerminalSettings.getParity()); - setFlowIn(m_TerminalSettings.getFlowControl()); - - m_wndSettingsGroup.layout(true); - } - - /** - * - */ - protected void setupNetworkPanel() - { - TerminalPlugin plugin; - TerminalProperties properties; - TerminalNetworkPortMap networkPortMap; - Label ctlLabel; - GridLayout gridLayout; - GridData gridData; - Vector table; - - if (m_wndSettingsPanel != null) - { - m_wndSettingsPanel.setVisible(false); - m_wndSettingsPanel.dispose(); - } - - plugin = TerminalPlugin.getDefault(); - properties = plugin.getTerminalProperties(); - m_wndSettingsPanel = new Composite(m_wndSettingsGroup,SWT.NONE); - gridLayout = new GridLayout(2,false); - gridData = new GridData(GridData.FILL_HORIZONTAL); - - m_wndSettingsPanel.setLayout(gridLayout); - m_wndSettingsPanel.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_HOST + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlHostText = new Text(m_wndSettingsPanel,SWT.BORDER); - m_ctlHostText.setLayoutData(gridData); - - // Add label - ctlLabel = new Label(m_wndSettingsPanel,SWT.RIGHT); - ctlLabel.setText(TERMINAL_TEXT_PORT + ":"); //$NON-NLS-1$ - - // Add control - gridData = new GridData(GridData.FILL_HORIZONTAL); - m_ctlNetworkPortCombo = new Combo(m_wndSettingsPanel,SWT.DROP_DOWN); - - m_ctlNetworkPortCombo.setLayoutData(gridData); - - networkPortMap = properties.getNetworkPortMap(); - table = networkPortMap.getNameTable(); - Collections.sort(table); - loadCombo(m_ctlNetworkPortCombo,table); - - setHost(m_TerminalSettings.getHost()); - setNetworkPort(m_TerminalSettings.getNetworkPort()); - - m_wndSettingsGroup.layout(true); - } - - /** - * - */ - protected void setupConnTypeNotSupportedPanel() - { - MessageDialog dlgError; - Shell parentShell; - Image imgTitle; - String labels[]; - String strTitle; - String strMessage; - int nImage; - int nIndex; - - if (m_wndSettingsPanel != null) - { - m_wndSettingsPanel.setVisible(false); - m_wndSettingsPanel.dispose(); - } - - m_wndSettingsPanel = new Composite(m_wndSettingsGroup,SWT.NONE); - parentShell = getShell(); - strTitle = TERMINAL_MSG_ERROR_5; - imgTitle = null; - strMessage = TERMINAL_MSG_ERROR_6; - nImage = SWT.ICON_ERROR; - labels = new String[]{"OK"}; //$NON-NLS-1$ - nIndex = 0; - dlgError = new MessageDialog(parentShell, - strTitle, - imgTitle, - strMessage, - nImage, - labels, - nIndex); - - m_wndSettingsGroup.layout(true); - dlgError.open(); - } - - /** - * - */ - protected void setupListeners() - { - TerminalSettingsSelectionHandler selectionHandler; - - selectionHandler = new TerminalSettingsSelectionHandler(); - m_ctlConnTypeCombo.addSelectionListener(selectionHandler); - } - - /** - * - */ - protected void loadCombo(Combo ctlCombo,Vector table) - { - String strData; - - for(int i=0;i - * - * @author Fran Litterio - * @author Chris Thew - */ -class TerminalText extends Thread implements ControlListener -{ - /** This is a character processing state: Initial state. */ - protected static final int ANSISTATE_INITIAL = 0; - - /** This is a character processing state: We've seen an escape character. */ - protected static final int ANSISTATE_ESCAPE = 1; - - /** - * This is a character processing state: We've seen a '[' after an escape - * character. Expecting a parameter character or a command character next. - */ - protected static final int ANSISTATE_EXPECTING_PARAMETER_OR_COMMAND = 2; - - /** - * This is a character processing state: We've seen a ']' after an escape - * character. We are now expecting an operating system command that reprograms an - * intelligent terminal. - */ - protected static final int ANSISTATE_EXPECTING_OS_COMMAND = 3; - - /** - * This field holds the current state of the Finite State Automaton (FSA) that - * recognizes ANSI escape sequences. - * - * @see #processNewText() - */ - protected int ansiState = ANSISTATE_INITIAL; - - /** - * This field holds a reference to the {@link TerminalCtrl} object that - * instantiates this class. - */ - protected TerminalCtrl terminal; - - /** - * This field holds a reference to the StyledText widget that is used to display - * text to the user. - */ - protected StyledText text; - - /** - * This field holds the characters received from the remote host before they are - * displayed to the user. Method {@link #processNewText()} scans this text - * looking for ANSI control characters and escape sequences. - */ - protected StringBuffer newText; - - /** - * This field holds the index of the current character while the text stored in - * field {@link #newText} is being processed. - */ - protected int characterIndex = 0; - - /** - * This field holds the width of a character (in pixels) for the font used to - * display text. - */ - protected int characterPixelWidth = 0; - - /** - * This field holds the width of the terminal screen in columns. - */ - protected int widthInColumns = 0; - - /** - * This field holds the height of the terminal screen in visible lines. The - * StyledText widget can contain more lines than are visible. - */ - protected int heightInLines = 0; - - /** - * 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.

- * - * 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.

- * - * When cursorColumn 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.

- */ - protected int cursorColumn = 0; - - /** - * This field holds the caret offset when we last moved it or wrote text to the - * terminal. The reason we need to remember this value is because, unlike with a - * normal terminal emulator, the user can move the caret by clicking anywhere in - * the terminal view. In a normal terminal emulator, the cursor only moves as the - * result of character output (i.e., escape sequences or normal characters). We - * use the value stored in this field to restore the position of the caret - * immediately before processing each chunk of output from the remote endpoint. - */ - protected int caretOffset = 0; - - /** - * This field hold the saved absolute line number of the cursor when processing the - * "ESC 7" and "ESC 8" command sequences. - */ - protected int savedCursorLine = 0; - - /** - * This field hold the saved column number of the cursor when processing the "ESC - * 7" and "ESC 8" command sequences. - */ - protected int savedCursorColumn = 0; - - /** - * This field holds an array of StringBuffer objects, each of which is one - * parameter from the current ANSI escape sequence. For example, when parsing the - * escape sequence "\e[20;10H", this array holds the strings "20" and "10". - */ - protected StringBuffer[] ansiParameters = new StringBuffer[16]; - - /** - * This field holds the OS-specific command found in an escape sequence of the form - * "\e]...\u0007". - */ - protected StringBuffer ansiOsCommand = new StringBuffer(128); - - /** - * This field holds the index of the next unused element of the array stored in - * field {@link #ansiParameters}. - */ - protected int nextAnsiParameter = 0; - - /** - * This field holds the Color object representing the current foreground color as - * set by the ANSI escape sequence "\e[m". - */ - protected Color currentForegroundColor; - - /** - * This field holds the Color object representing the current background color as - * set by the ANSI escape sequence "\e[m". - */ - protected Color currentBackgroundColor; - - /** - * This field holds an integer representing the current font style as set by the - * ANSI escape sequence "\e[m". - */ - protected int currentFontStyle = SWT.NORMAL; - - /** - * This field is true if we are currently outputing text in reverse video mode, - * false otherwise. - */ - protected boolean reverseVideo = false; - - /** - * This field holds the time (in milliseconds) of the previous call to method - * {@link #SetNewText()}. - */ - static long LastNewOutputTime = 0; - - /** - * Color object representing the color black. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color BLACK = new Color(Display.getCurrent(), 0, 0, 0); - - /** - * Color object representing the color red. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color RED = new Color(Display.getCurrent(), 255, 0, 0); - - /** - * Color object representing the color green. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color GREEN = new Color(Display.getCurrent(), 0, 255, 0); - - /** - * Color object representing the color yellow. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color YELLOW = new Color(Display.getCurrent(), 255, 255, 0); - - /** - * Color object representing the color blue. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color BLUE = new Color(Display.getCurrent(), 0, 0, 255); - - /** - * Color object representing the color magenta. The Color class requires us to - * call dispose() on this object when we no longer need it. We do that in method - * {@link #dispose()}. - */ - protected final Color MAGENTA = new Color(Display.getCurrent(), 255, 0, 255); - - /** - * Color object representing the color cyan. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color CYAN = new Color(Display.getCurrent(), 0, 255, 255); - - /** - * Color object representing the color white. The Color class requires us to call - * dispose() on this object when we no longer need it. We do that in method {@link - * #dispose()}. - */ - protected final Color WHITE = new Color(Display.getCurrent(), 255, 255, 255); - - /** - * The constructor. - */ - public TerminalText(TerminalCtrl terminal) - { - super(); - - Logger.log("entered"); //$NON-NLS-1$ - - this.terminal = terminal; - - for (int i = 0; i < ansiParameters.length; ++i) - { - ansiParameters[i] = new StringBuffer(); - } - } - - /** - * This method performs clean up when this TerminalText object is no longer - * needed. After calling this method, no other method on this object should be - * called. - */ - public void dispose() - { - Logger.log("entered"); //$NON-NLS-1$ - - // Call dispose() on the Color objects we created. - - BLACK.dispose(); - RED.dispose(); - GREEN.dispose(); - YELLOW.dispose(); - BLUE.dispose(); - MAGENTA.dispose(); - CYAN.dispose(); - WHITE.dispose(); - } - - /** - * This method is required by interface ControlListener. It allows us to know when - * the StyledText widget is moved. - */ - public void controlMoved(ControlEvent event) - { - Logger.log("entered"); //$NON-NLS-1$ - // Empty. - } - - /** - * This method is required by interface ControlListener. It allows us to know when - * the StyledText widget is resized. This method must be synchronized to prevent - * it from executing at the same time as run(), which displays new text. We can't - * have the fields that represent the dimensions of the terminal changing while we - * are rendering text. - */ - public synchronized void controlResized(ControlEvent event) - { - Logger.log("entered"); //$NON-NLS-1$ - adjustTerminalDimensions(); - } - - /** - * This method sets field {@link #newText} to a new value. This method must - * not execute at the same time as methods {@link #run()} and {@link - * #clearTerminal()}.

- * - * IMPORTANT: This method must be called in strict alternation with method - * {@link #run()}.

- * - * @param newBuffer The new buffer containing characters received from the - * remote host. - */ - public synchronized void setNewText(StringBuffer newBuffer) - { - Logger.log("new text: '" + newBuffer + "'"); //$NON-NLS-1$ //$NON-NLS-2$ - newText = newBuffer; - - // When continuous output is being processed by the Terminal view code, it - // consumes nearly 100% of the CPU. This fixes that. If this method is called - // too frequently, we explicitly sleep for a short time so that the thread - // executing this function (which is the thread reading from the socket or - // serial port) doesn't consume 100% of the CPU. Without this code, the - // Workbench GUI is practically hung when there is continuous output in the - // Terminal view. - - long CurrentTime = System.currentTimeMillis(); - - if (CurrentTime - LastNewOutputTime < 250 && newBuffer.length() > 10) - { - try - { - Thread.sleep(50); - } - catch (InterruptedException ex) - { - // Ignore. - } - } - - LastNewOutputTime = CurrentTime; - } - - /** - * This method erases all text from the Terminal view. This method is called when - * the user chooses "Clear all" from the Terminal view context menu, so we need to - * serialize this method with methods {@link #run()} and {@link - * #setNewText(StringBuffer)}. - */ - public synchronized void clearTerminal() - { - Logger.log("entered"); //$NON-NLS-1$ - text.setText(""); //$NON-NLS-1$ - cursorColumn = 0; - } - - /** - * This method is called when the user changes the Terminal view's font. We - * attempt to recompute the pixel width of the new font's characters and fix the - * terminal's dimensions. This method must be synchronized to prevent it from - * executing at the same time as run(), which displays new text. We can't have the - * fields that represent the dimensions of the terminal changing while we are - * rendering text. - */ - public synchronized void fontChanged() - { - Logger.log("entered"); //$NON-NLS-1$ - - characterPixelWidth = 0; - - if (text != null) - adjustTerminalDimensions(); - } - - /** - * This method executes in the Display thread to process data received from the - * remote host by classes {@link TelnetConnection} and {@link - * TerminalSerialPortHandler}. This method must not execute at the same time as - * methods {@link #setNewText(StringBuffer)} and {@link #clearTerminal()}.

- * - * IMPORTANT: This method must be called in strict alternation with method - * {@link #setNewText(StringBuffer)}.

- */ - public synchronized void run() - { - Logger.log("entered"); //$NON-NLS-1$ - - try - { - if (text == null) - { - // We defer initialization of these fields until execution reaches - // here, because the StyledText widget doesn't exist when this class is - // first instantiated. - - text = terminal.getTextWidget(); - - // Register this class instance as a ControlListener so we can learn - // when the StyledText widget is resized. - - text.addControlListener(this); - - currentForegroundColor = text.getForeground(); - currentBackgroundColor = text.getBackground(); - currentFontStyle = SWT.NORMAL; - reverseVideo = false; - } - - // This method can be called just after the user closes the view, so we - // make sure not to cause a widget-disposed exception. - - if (text != null && text.isDisposed()) - return; - - // If the status bar is showing "OPENED", change it to "CONNECTED". - - if (terminal.isOpened()) - { - terminal.setOpened(false); - terminal.execute(TerminalMsg.ON_TERMINAL_STATUS, null); - } - - // Find the width and height of the terminal, and resize it to display an - // integral number of lines and columns. - - adjustTerminalDimensions(); - - // Restore the caret offset, process and display the new text, then save - // the caret offset. See the documentation for field caretOffset for - // details. - - // ISSUE: Is this causing the scroll-to-bottom-on-output behavior? - - text.setCaretOffset(caretOffset); - - processNewText(); - - caretOffset = text.getCaretOffset(); - } - catch (Exception ex) - { - Logger.logException(ex); - } - } - - /** - * This method scans the newly received text, processing ANSI control characters - * and escape sequences and displaying normal text. - */ - protected void processNewText() - { - Logger.log("entered"); //$NON-NLS-1$ - - // Stop the StyledText widget from redrawing while we manipulate its contents. - // This helps display performance. - - text.setRedraw(false); - - // Scan the newly received text. - - characterIndex = 0; - - while (characterIndex < newText.length()) - { - char character = newText.charAt(characterIndex); - - switch (ansiState) - { - case ANSISTATE_INITIAL: - switch (character) - { - case '\u0000': - break; // NUL character. Ignore it. - - case '\u0007': - processBEL(); // BEL (Ctrl-G) - break; - - case '\b': - processBackspace(); // Backspace - break; - - case '\t': - processTab(); // Tab. - break; - - case '\n': - processNewline(); // Newline (Ctrl-J) - break; - - case '\r': - processCarriageReturn(); // Carriage Return (Ctrl-M) - break; - - case '\u001b': - ansiState = ANSISTATE_ESCAPE; // Escape. - break; - - default: - processNonControlCharacters(); - break; - } - break; - - case ANSISTATE_ESCAPE: - // We've seen an escape character. Here, we process the character - // immediately following the escape. - - switch (character) - { - case '[': - ansiState = ANSISTATE_EXPECTING_PARAMETER_OR_COMMAND; - nextAnsiParameter = 0; - - // Erase the parameter strings in preparation for optional - // parameter characters. - - for (int i = 0; i < ansiParameters.length; ++i) - { - ansiParameters[i].delete(0, ansiParameters[i].length()); - } - break; - - case ']': - ansiState = ANSISTATE_EXPECTING_OS_COMMAND; - ansiOsCommand.delete(0, ansiOsCommand.length()); - break; - - case '7': - // Save cursor position and character attributes - - ansiState = ANSISTATE_INITIAL; - savedCursorLine = absoluteCursorLine(); - savedCursorColumn = cursorColumn; - break; - - case '8': - // Restore cursor and attributes to previously saved position - - ansiState = ANSISTATE_INITIAL; - moveCursor(savedCursorLine, savedCursorColumn); - break; - - default: - Logger.log("Unsupported escape sequence: escape '" + character + "'"); //$NON-NLS-1$ //$NON-NLS-2$ - ansiState = ANSISTATE_INITIAL; - break; - } - break; - - case ANSISTATE_EXPECTING_PARAMETER_OR_COMMAND: - // Parameters can appear after the '[' in an escape sequence, but they - // are optional. - - if (character == '@' || - (character >= 'A' && character <= 'Z') || - (character >= 'a' && character <= 'z')) - { - ansiState = ANSISTATE_INITIAL; - processAnsiCommandCharacter(character); - } - else - { - processAnsiParameterCharacter(character); - } - break; - - case ANSISTATE_EXPECTING_OS_COMMAND: - // A BEL (\u0007) character marks the end of the OSC sequence. - - if (character == '\u0007') - { - ansiState = ANSISTATE_INITIAL; - processAnsiOsCommand(); - } - else - { - ansiOsCommand.append(character); - } - break; - - default: - // This should never happen! If it does happen, it means there is a - // bug in the FSA. For robustness, we return to the initial state. - - Logger.log("INVALID ANSI FSA STATE: " + ansiState); //$NON-NLS-1$ - ansiState = ANSISTATE_INITIAL; - assert false; - break; - } - - ++characterIndex; - } - - // Allow the StyledText widget to redraw itself. - - text.setRedraw(true); - } - - /** - * This method is called when we have parsed an OS Command escape sequence. The - * only one we support is "\e]0;...\u0007", which sets the terminal title. - */ - protected void processAnsiOsCommand() - { - if (ansiOsCommand.charAt(0) != '0' || ansiOsCommand.charAt(1) != ';') - { - Logger.log("Ignoring unsupported ANSI OSC sequence: '" + ansiOsCommand + "'"); //$NON-NLS-1$ //$NON-NLS-2$ - return; - } - - terminal.execute(TerminalMsg.ON_TERMINAL_STATUS, ansiOsCommand.substring(2)); - } - - /** - * This method dispatches control to various processing methods based on the - * command character found in the most recently received ANSI escape sequence. - * This method only handles command characters that follow the ANSI standard - * Control Sequence Introducer (CSI), which is "\e[...", where "..." is an optional - * ';'-separated sequence of numeric parameters.

- */ - protected void processAnsiCommandCharacter(char ansiCommandCharacter) - { - // If the width or height of the terminal is ridiculously small (one line or - // column or less), don't even try to process the escape sequence. This avoids - // throwing an exception (SPR 107450). The display will be messed up, but what - // did you user expect by making the terminal so small? - - if (heightInLines <= 1 || widthInColumns <= 1) - return; - - switch (ansiCommandCharacter) - { - case '@': - // Insert character(s). - processAnsiCommand_atsign(); - break; - - case 'A': - // Move cursor up N lines (default 1). - processAnsiCommand_A(); - break; - - case 'B': - // Move cursor down N lines (default 1). - processAnsiCommand_B(); - break; - - case 'C': - // Move cursor forward N columns (default 1). - processAnsiCommand_C(); - break; - - case 'D': - // Move cursor backward N columns (default 1). - processAnsiCommand_D(); - break; - - case 'E': - // Move cursor to first column of Nth next line (default 1). - processAnsiCommand_E(); - break; - - case 'F': - // Move cursor to first column of Nth previous line (default 1). - processAnsiCommand_F(); - break; - - case 'G': - // Move to column N of current line (default 1). - processAnsiCommand_G(); - break; - - case 'H': - // Set cursor Position. - processAnsiCommand_H(); - break; - - case 'J': - // Erase part or all of display. Cursor does not move. - processAnsiCommand_J(); - break; - - case 'K': - // Erase in line (cursor does not move). - processAnsiCommand_K(); - break; - - case 'L': - // Insert line(s) (current line moves down). - processAnsiCommand_L(); - break; - - case 'M': - // Delete line(s). - processAnsiCommand_M(); - break; - - case 'm': - // Set Graphics Rendition (SGR). - processAnsiCommand_m(); - break; - - case 'n': - // Device Status Report (DSR). - processAnsiCommand_n(); - break; - - case 'P': - // Delete character(s). - processAnsiCommand_P(); - break; - - case 'S': - // Scroll up. - // Emacs, vi, and GNU readline don't seem to use this command, so we ignore - // it for now. - break; - - case 'T': - // Scroll down. - // Emacs, vi, and GNU readline don't seem to use this command, so we ignore - // it for now. - break; - - case 'X': - // Erase character. - // Emacs, vi, and GNU readline don't seem to use this command, so we ignore - // it for now. - break; - - case 'Z': - // Cursor back tab. - // Emacs, vi, and GNU readline don't seem to use this command, so we ignore - // it for now. - break; - - default: - Logger.log("Ignoring unsupported ANSI command character: '" + //$NON-NLS-1$ - ansiCommandCharacter + "'"); //$NON-NLS-1$ - break; - } - } - - /** - * 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 hte - * line. - */ - protected void processAnsiCommand_atsign() - { - int charactersToInsert = getAnsiParameter(0); - int caretOffset = text.getCaretOffset(); - - text.replaceTextRange(caretOffset, 0, generateString(' ', charactersToInsert)); - - // If the current line extends past the right edge of the screen, delete the - // characters beyond the rightmost visible column. - - int currentLineAbsolute = absoluteCursorLine(); - int currentLineStartOffset = text.getOffsetAtLine(currentLineAbsolute); - int currentLineEndOffset; - - if (currentLineAbsolute == text.getLineCount() - 1) - { - // The cursor is on the bottommost line of text. - - currentLineEndOffset = text.getCharCount(); - } - else - { - // The cursor is not on the bottommost line of text. - - currentLineEndOffset = text.getOffsetAtLine(currentLineAbsolute + 1) - 1; - } - - if (currentLineEndOffset - currentLineStartOffset > widthInColumns) - { - int charactersToDelete = - currentLineEndOffset - currentLineStartOffset - widthInColumns; - - text.replaceTextRange(currentLineStartOffset + widthInColumns, - charactersToDelete, ""); //$NON-NLS-1$ - } - - // Is this necessary? - - text.setCaretOffset(caretOffset); - } - - /** - * This method moves the cursor up by the number of lines specified by the escape - * sequence parameter (default 1). - */ - protected void processAnsiCommand_A() - { - moveCursorUp(getAnsiParameter(0)); - } - - /** - * This method moves the cursor down by the number of lines specified by the escape - * sequence parameter (default 1). - */ - protected void processAnsiCommand_B() - { - moveCursorDown(getAnsiParameter(0)); - } - - /** - * This method moves the cursor forward by the number of columns specified by the - * escape sequence parameter (default 1). - */ - protected void processAnsiCommand_C() - { - moveCursorForward(getAnsiParameter(0)); - } - - /** - * This method moves the cursor backward by the number of columns specified by the - * escape sequence parameter (default 1). - */ - protected void processAnsiCommand_D() - { - moveCursorBackward(getAnsiParameter(0)); - } - - /** - * This method moves the cursor to the first column of the Nth next line, where N - * is specified by the ANSI parameter (default 1). - */ - protected void processAnsiCommand_E() - { - int linesToMove = getAnsiParameter(0); - - moveCursor(relativeCursorLine() + linesToMove, 0); - } - - /** - * This method moves the cursor to the first column of the Nth previous line, where - * N is specified by the ANSI parameter (default 1). - */ - protected void processAnsiCommand_F() - { - int linesToMove = getAnsiParameter(0); - - moveCursor(relativeCursorLine() - linesToMove, 0); - } - - /** - * This method moves the cursor within the current line to the column specified by - * the ANSI parameter (default is column 1). - */ - protected void processAnsiCommand_G() - { - int targetColumn = 1; - - if (ansiParameters[0].length() > 0) - targetColumn = getAnsiParameter(0) - 1; - - moveCursor(relativeCursorLine(), targetColumn); - } - - /** - * This method sets the cursor to a position specified by the escape sequence - * parameters (default is the upper left corner of the screen). - */ - protected void processAnsiCommand_H() - { - moveCursor(getAnsiParameter(0) - 1, getAnsiParameter(1) - 1); - } - - /** - * This method deletes some (or all) of the text on the screen without moving the - * cursor. - */ - protected void processAnsiCommand_J() - { - int ansiParameter; - - if (ansiParameters[0].length() == 0) - ansiParameter = 0; - else - ansiParameter = getAnsiParameter(0); - - switch (ansiParameter) - { - case 0: - // Erase from current position to end of screen (inclusive). - - int caretOffset = text.getCaretOffset(); - - text.replaceTextRange(caretOffset, - text.getCharCount() - caretOffset, - generateString('\n', heightInLines - relativeCursorLine() - 1)); - - // The above call moves the caret to the end of the text, so restore its - // position. - - text.setCaretOffset(caretOffset); - break; - - case 1: - // Erase from beginning to current position (inclusive). - - int currentRelativeLineNumber = relativeCursorLine(); - int topmostScreenLineStartOffset = text.getOffsetAtLine(absoluteLine(0)); - - text.replaceTextRange(topmostScreenLineStartOffset, - text.getCaretOffset() - topmostScreenLineStartOffset, - generateString('\n', currentRelativeLineNumber) + - generateString(' ', cursorColumn)); - - text.setCaretOffset(topmostScreenLineStartOffset + currentRelativeLineNumber + - cursorColumn); - break; - - case 2: - // Erase entire display. - - int currentLineNumber = relativeCursorLine(); - topmostScreenLineStartOffset = text.getOffsetAtLine(absoluteLine(0)); - - text.replaceTextRange(topmostScreenLineStartOffset, - text.getCharCount() - topmostScreenLineStartOffset, - generateString('\n', heightInLines - 1)); - - moveCursor(currentLineNumber, cursorColumn); - break; - - default: - Logger.log("Unexpected J-command parameter: " + ansiParameter); //$NON-NLS-1$ - assert false; - break; - } - } - - /** - * This method deletes some (or all) of the text in the current line without moving - * the cursor. - */ - protected void processAnsiCommand_K() - { - int ansiParameter = getAnsiParameter(0); - int originalCaretOffset = text.getCaretOffset(); - - switch (ansiParameter) - { - case 0: - // Erase from beginning to current position (inclusive). - - int currentLineStartOffset = text.getOffsetAtLine(absoluteCursorLine()); - - text.replaceTextRange(currentLineStartOffset, - cursorColumn, - generateString(' ', cursorColumn)); - break; - - case 1: - // Erase from current position to end (inclusive). - - int caretOffset = text.getCaretOffset(); - - if (absoluteCursorLine() == text.getLineCount() - 1) - { - text.replaceTextRange(caretOffset, text.getCharCount() - caretOffset, ""); //$NON-NLS-1$ - } - else - { - int nextLineStartOffset = text.getOffsetAtLine(absoluteCursorLine() + 1); - - text.replaceTextRange(caretOffset, nextLineStartOffset - caretOffset - 1, ""); //$NON-NLS-1$ - } - break; - - case 2: - // Erase entire line. - - currentLineStartOffset = text.getOffsetAtLine(absoluteCursorLine()); - - if (absoluteCursorLine() == text.getLineCount() - 1) - { - // The cursor is on the bottommost line of text. Replace its contents - // with enough spaces to leave the cursor in the current column. - - text.replaceTextRange(currentLineStartOffset, - text.getCharCount() - currentLineStartOffset, - generateString(' ', cursorColumn)); - } - else - { - // The cursor is not on the bottommost line of text. Replace the - // current line's contents with enough spaces to leave the cursor in - // the current column. - - int nextLineStartOffset = text.getOffsetAtLine(absoluteCursorLine() + 1); - - text.replaceTextRange(currentLineStartOffset, - nextLineStartOffset - currentLineStartOffset - 1, - generateString(' ', cursorColumn)); - } - break; - - default: - Logger.log("Unexpected K-command parameter: " + ansiParameter); //$NON-NLS-1$ - assert false; - break; - } - - // There is some undocumented strangeness with method - // StyledText.replaceTextRange() that requires us to manually reposition the - // caret after calling that method. If we don't do this, the caret sometimes - // moves to the very end of the text when deleting text within a line. - - text.setCaretOffset(originalCaretOffset); - } - - /** - * Insert one or more blank lines. The current line of text moves down. Text that - * falls off the bottom of the screen is deleted. - */ - protected void processAnsiCommand_L() - { - int linesToInsert = getAnsiParameter(0); - - int currentLineStartOffset = text.getOffsetAtLine(absoluteCursorLine()); - - // Compute how many of the bottommost lines of text to delete. This is - // necessary if those lines are being pushed off the bottom of the screen by - // the insertion of the blank lines. - - int totalLines = text.getLineCount(); - int linesToDelete = -1; - - if (heightInLines <= totalLines) - { - // There are more lines of text than are displayed, so delete as many lines - // at the end as we insert in the middle. - - linesToDelete = linesToInsert; - } - else - { - // There are fewer lines of text than the size of the terminal window, so - // compute how many lines will be pushed off the end of the screen by the - // insertion. NOTE: It is possible that we may not have to delete any - // lines at all, which will leave linesToDelete set to -1. - - if (totalLines + linesToInsert > heightInLines) - { - linesToDelete = (totalLines + linesToInsert) - heightInLines; - } - } - - if (linesToDelete != -1) - { - // Delete the bottomost linesToInsert lines plus the newline on the line - // immediately above the first line to be deleted. - - int firstLineToDeleteStartOffset = text.getOffsetAtLine(totalLines - linesToDelete); - - text.replaceTextRange(firstLineToDeleteStartOffset - 1, - text.getCharCount() - firstLineToDeleteStartOffset + 1, - ""); //$NON-NLS-1$ - } - - // Insert the new blank lines, leaving the cursor on the topmost of the new - // blank lines. - - int totalCharacters = text.getCharCount(); - - if (currentLineStartOffset > totalCharacters) - { - // We are inserting the blank lines at the very end of the text, so - // currentLineStartOffset is now out of range. It will be be in range - // again after these newlines are appended. - - text.replaceTextRange(totalCharacters, 0, generateString('\n', linesToInsert)); - } - else - { - // We are inserting the blank lines in the middle of the text, so - // currentLineStartOffset is not out of range. - - text.replaceTextRange(currentLineStartOffset, 0, generateString('\n', linesToInsert)); - } - - text.setCaretOffset(currentLineStartOffset); - } - - /** - * Delete one or more lines of text. Any lines below the deleted lines move up, - * which we implmement by appending newlines to the end of the text. - */ - protected void processAnsiCommand_M() - { - int totalLines = text.getLineCount(); - int linesToDelete = getAnsiParameter(0); - int currentLineAbsolute = absoluteCursorLine(); - int currentLineStartOffset = text.getOffsetAtLine(currentLineAbsolute); - - // Compute the offset of the character after the lines to be deleted. This - // might be the end of the text. - - if (linesToDelete >= totalLines - currentLineAbsolute) - { - // We are deleting all the lines to the bottom of the text. Replace them - // with blank lines. - - text.replaceTextRange(currentLineStartOffset, - text.getCharCount() - currentLineStartOffset, - generateString('\n', totalLines - currentLineAbsolute - 1)); - } - else - { - // Delete the next linesToDelete lines. - - int firstUndeletedLineStartOffset = - text.getOffsetAtLine(currentLineAbsolute + linesToDelete); - - text.replaceTextRange(currentLineStartOffset, - firstUndeletedLineStartOffset - currentLineStartOffset, - ""); //$NON-NLS-1$ - - // Add an equal number of blank lines to the end of the text. - - text.replaceTextRange(text.getCharCount(), 0, generateString('\n', linesToDelete)); - } - - text.setCaretOffset(currentLineStartOffset); - } - - /** - * This method sets a new graphics rendition mode, such as foreground/background - * color, bold/normal text, and reverse video. - */ - protected void processAnsiCommand_m() - { - if (ansiParameters[0].length() == 0) - { - // This a special case: when no ANSI parameter is specified, act like a - // single parameter equal to 0 was specified. - - ansiParameters[0].append('0'); - } - - // There are a non-zero number of ANSI parameters. Process each one in order. - - int totalParameters = ansiParameters.length; - int parameterIndex = 0; - - while (parameterIndex < totalParameters && ansiParameters[parameterIndex].length() > 0) - { - int ansiParameter = getAnsiParameter(parameterIndex); - - switch (ansiParameter) - { - case 0: - // Reset all graphics modes. - currentForegroundColor = text.getForeground(); - currentBackgroundColor = text.getBackground(); - currentFontStyle = SWT.NORMAL; - reverseVideo = false; - break; - - case 1: - currentFontStyle = SWT.BOLD; // Turn on bold. - break; - - case 7: - reverseVideo = true; // Reverse video. - break; - - case 10: // Set primary font. Ignored. - break; - - case 22: - currentFontStyle = SWT.NORMAL; // Cancel bold or dim attributes only. - break; - - case 27: - reverseVideo = false; // Cancel reverse video attribute only. - break; - - case 30: - currentForegroundColor = BLACK; // Foreground is black. - break; - - case 31: - currentForegroundColor = RED; // Foreground is red. - break; - - case 32: - currentForegroundColor = GREEN; // Foreground is green. - break; - - case 33: - currentForegroundColor = YELLOW; // Foreground is yellow. - break; - - case 34: - currentForegroundColor = BLUE; // Foreground is blue. - break; - - case 35: - currentForegroundColor = MAGENTA; // Foreground is magenta. - break; - - case 36: - currentForegroundColor = CYAN; // Foreground is cyan. - break; - - case 37: - currentForegroundColor = text.getForeground(); // Foreground is white. - break; - - case 40: - currentBackgroundColor = text.getBackground(); // Background is black. - break; - - case 41: - currentBackgroundColor = RED; // Background is red. - break; - - case 42: - currentBackgroundColor = GREEN; // Background is green. - break; - - case 43: - currentBackgroundColor = YELLOW; // Background is yellow. - break; - - case 44: - currentBackgroundColor = BLUE; // Background is blue. - break; - - case 45: - currentBackgroundColor = MAGENTA; // Background is magenta. - break; - - case 46: - currentBackgroundColor = CYAN; // Background is cyan. - break; - - case 47: - currentBackgroundColor = WHITE; // Background is white. - break; - - default: - Logger.log("Unsupported graphics rendition parameter: " + ansiParameter); //$NON-NLS-1$ - break; - } - - ++ parameterIndex; - } - } - - /** - * This method responds to an ANSI Device Status Report (DSR) command from the - * remote endpoint requesting the cursor position. Requests for other kinds of - * status are ignored. - */ - protected void processAnsiCommand_n() - { - // Do nothing if the numeric parameter was not 6 (which means report cursor - // position). - - if (getAnsiParameter(0) != 6) - return; - - // Send the ANSI cursor position (which is 1-based) to the remote endpoint. - - String positionReport = "\u001b[" + (relativeCursorLine() + 1) + ";" + //$NON-NLS-1$ //$NON-NLS-2$ - (cursorColumn + 1) + "R"; //$NON-NLS-1$ - - OutputStreamWriter streamWriter = - new OutputStreamWriter(terminal.getOutputStream(), Charset.forName("ISO-8859-1")); //$NON-NLS-1$ - - try - { - streamWriter.write(positionReport, 0, positionReport.length()); - streamWriter.flush(); - } - catch (IOException ex) - { - Logger.log("Caught IOException!"); //$NON-NLS-1$ - assert false; - } - } - - /** - * Deletes one or more characters starting at the current cursor position. - * Characters on the same line and to the right of the deleted characters move - * left. If there are no characters on the current line at or to the right of the - * cursor column, no text is deleted. - */ - protected void processAnsiCommand_P() - { - int currentLineEndOffset; - int currentLineAbsolute = absoluteCursorLine(); - - if (currentLineAbsolute == text.getLineCount() - 1) - { - // The cursor is on the bottommost line of text. - - currentLineEndOffset = text.getCharCount(); - } - else - { - // The cursor is not on the bottommost line of text. - - currentLineEndOffset = text.getOffsetAtLine(currentLineAbsolute + 1) - 1; - } - - int caretOffset = text.getCaretOffset(); - int remainingCharactersOnLine = currentLineEndOffset - caretOffset; - - if (remainingCharactersOnLine > 0) - { - // There are characters that can be deleted. - - int charactersToDelete = getAnsiParameter(0); - - if (charactersToDelete > remainingCharactersOnLine) - charactersToDelete = remainingCharactersOnLine; - - text.replaceTextRange(caretOffset, charactersToDelete, ""); //$NON-NLS-1$ - text.setCaretOffset(caretOffset); - } - } - - /** - * This method returns one of the numeric ANSI parameters received in the most - * recent escape sequence. - * - * @return The parameterIndexth numeric ANSI parameter or -1 if the index - * is out of range. - */ - protected int getAnsiParameter(int parameterIndex) - { - if (parameterIndex < 0 || parameterIndex >= ansiParameters.length) - { - // This should never happen. - assert false; - return -1; - } - - String parameter = ansiParameters[parameterIndex].toString(); - - if (parameter.length() == 0) - return 1; - - int parameterValue = 1; - - // Don't trust the remote endpoint to send well formed numeric parameters. - - try - { - parameterValue = Integer.parseInt(parameter); - } - catch (NumberFormatException ex) - { - parameterValue = 1; - } - - return parameterValue; - } - - /** - * This method processes a single parameter character in an ANSI escape sequence. - * Paramters are the (optional) characters between the leading "\e[" and the - * command character in an escape sequence (e.g., in the escape sequence - * "\e[20;10H", the paramter characters are "20;10"). Parameters are integers - * separated by one or more ';'s. - */ - protected void processAnsiParameterCharacter(char ch) - { - if (ch == ';') - { - ++nextAnsiParameter; - } - else - { - if (nextAnsiParameter < ansiParameters.length) - ansiParameters[nextAnsiParameter].append(ch); - } - } - - /** - * This method processes a contiguous sequence of non-control characters. This is - * a performance optimization, so that we don't have to insert or append each - * non-control character individually to the StyledText widget. A non-control - * character is any character that passes the condition in the below while loop. - */ - protected void processNonControlCharacters() - { - int firstNonControlCharacterIndex = characterIndex; - int newTextLength = newText.length(); - char character = newText.charAt(characterIndex); - - // Identify a contiguous sequence of non-control characters, starting at - // firstNonControlCharacterIndex in newText. - - while (character != '\u0000' && character != '\b' && character != '\t' && - character != '\u0007' && character != '\n' && character != '\r' && - character != '\u001b') - { - ++characterIndex; - - if (characterIndex >= newTextLength) - break; - - character = newText.charAt(characterIndex); - } - - // Move characterIndex back by one character because it gets incremented at the - // bottom of the loop in processNewText(). - - --characterIndex; - - int preDisplayCaretOffset = text.getCaretOffset(); - - // Now insert the sequence of non-control characters in the StyledText widget - // at the location of the cursor. - - displayNewText(firstNonControlCharacterIndex, characterIndex); - - // If any one of the current font style, foreground color or background color - // differs from the defaults, apply the current style to the newly displayed - // text. Since this method is only called for a contiguous sequence of - // non-control characters, the current style applies to the entire sequence of - // characters. - - if (!currentForegroundColor.equals(text.getForeground()) || - !currentBackgroundColor.equals(text.getBackground()) || - currentFontStyle != SWT.NORMAL || - reverseVideo == true) - { - StyleRange style = - new StyleRange(preDisplayCaretOffset, - text.getCaretOffset() - preDisplayCaretOffset, - reverseVideo ? currentBackgroundColor : currentForegroundColor, - reverseVideo ? currentForegroundColor : currentBackgroundColor, - currentFontStyle); - - text.setStyleRange(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.

- * - * 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).

- * - * @param first The index (within newText) of the first character to - * display. - * @param last The index (within newText) of the last character to - * display. - */ - protected void displayNewText(int first, int last) - { - if (text.getCaretOffset() == text.getCharCount()) - { - // The cursor is at the very end of the terminal's text, so we append the - // new text to the StyledText widget. - - displayNewTextByAppending(first, last); - } - else - { - // The cursor is not at the end of the screen's text, so we have to - // overwrite existing text. - - displayNewTextByOverwriting(first, last); - } - } - - /** - * This method displays new text by appending it to the end of the existing text, - * wrapping text that extends past the right edge of the screen.

- * - * 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).

- * - * @param first The index (within newText) of the first character to - * display. - * @param last The index (within newText) of the last character to - * display. - */ - protected void displayNewTextByAppending(int first, int last) - { - int numCharsToOutput = last - first + 1; - int availableSpaceOnLine = widthInColumns - cursorColumn; - - if (numCharsToOutput >= availableSpaceOnLine) - { - // We need to wrap the text, because it's longer than the available - // space on the current line. First, appends as many characters as - // will fit in the space remaining on the current line. - // - // NOTE: We don't line wrap the text in this method the same way we line - // wrap the text in method displayNewTextByOverwriting(), but this is by far - // the most common case, and it has to run the fastest. - - text.append(newText.substring(first, first + availableSpaceOnLine)); - first += availableSpaceOnLine; - - processCarriageReturn(); - processNewline(); - - while (first <= last) - { - availableSpaceOnLine = widthInColumns; - - if (availableSpaceOnLine > last - first + 1) - { - text.append(newText.substring(first, last + 1)); - cursorColumn = last - first + 1; - break; - } - else - { - text.append(newText.substring(first, first + availableSpaceOnLine)); - first += availableSpaceOnLine; - - processCarriageReturn(); - processNewline(); - } - } - } - else - { - // We don't need to wrap the text. - - text.append(newText.substring(first, last + 1)); - cursorColumn += last - first + 1; - } - } - - /** - * This method displays new text by overwriting existing text, wrapping text that - * extends past the right edge of the screen.

- * - * 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).

- * - * @param first The index (within newText) of the first character to - * display. - * @param last The index (within newText) of the last character to - * display. - */ - protected void displayNewTextByOverwriting(int first, int last) - { - // First, break new text into segments, based on where it needs to line wrap, - // so that each segment contains text that will appear on a separate line. - - List textSegments = new ArrayList(100); - - int availableSpaceOnLine = widthInColumns - cursorColumn; - - while (first <= last) - { - String segment; - - if (last - first + 1 > availableSpaceOnLine) - segment = newText.substring(first, first + availableSpaceOnLine); - else - segment = newText.substring(first, last + 1); - - textSegments.add(segment); - - first += availableSpaceOnLine; - availableSpaceOnLine = widthInColumns; - } - - // Next, for each segment, if the cursor is at the end of the text, append the - // segment along with a newline character. If the cursor is not at the end of - // the text, replace the next N characters starting at the cursor position with - // the segment, where N is the minimum of the length of the segment or the - // length of the rest of the current line. - - Iterator iter = textSegments.iterator(); - - while (iter.hasNext()) - { - String segment = (String)iter.next(); - int caretOffset = text.getCaretOffset(); - - if (caretOffset == text.getCharCount()) - { - // The cursor is at the end of the text, so just append the current - // segement along with a newline. - - text.append(segment); - - // If there is another segment to display, move the cursor to a new - // line. - - if (iter.hasNext()) - { - processCarriageReturn(); - processNewline(); - } - } - else - { - // The cursor is not at the end of the text, so replace some or all of - // the text following the cursor on the current line with the current - // segment. - - int numCharactersAfterCursorOnLine; - - if (absoluteCursorLine() == text.getLineCount() - 1) - { - // The cursor is on the last line of text. - numCharactersAfterCursorOnLine = text.getCharCount() - caretOffset; - } - else - { - // The cursor is not on the last line of text. - numCharactersAfterCursorOnLine = - text.getOffsetAtLine(absoluteCursorLine() + 1) - caretOffset - 1; - } - - int segmentLength = segment.length(); - int numCharactersToReplace; - - if (segmentLength < numCharactersAfterCursorOnLine) - numCharactersToReplace = segmentLength; - else - numCharactersToReplace = numCharactersAfterCursorOnLine; - - text.replaceTextRange(caretOffset, numCharactersToReplace, segment); - text.setCaretOffset(caretOffset + segmentLength); - cursorColumn += segmentLength; - - // If there is another segment, move the cursor to the start of the - // next line. - - if (iter.hasNext()) - { - cursorColumn = 0; - text.setCaretOffset(caretOffset + segmentLength + 1); - } - else - { - // We just inserted the last segment. If the current line is full, - // wrap the cursor onto a new line. - - if (cursorColumn == widthInColumns) - { - processCarriageReturn(); - processNewline(); - } - } - } - } - } - - /** - * Process a BEL (Ctrl-G) character. - */ - protected void processBEL() - { - // ISSUE: Is there a better way to make a sound? This is not guaranteed to - // work on all platforms. - - java.awt.Toolkit.getDefaultToolkit().beep(); - } - - /** - * Process a backspace (Ctrl-H) character. - */ - protected void processBackspace() - { - moveCursorBackward(1); - } - - /** - * Process a tab (Ctrl-I) character. We don't insert a tab character into the - * StyledText widget. Instead, we move the cursor forward to the next tab stop, - * without altering any of the text. Tab stops are every 8 columns. The cursor - * will never move past the rightmost column. - */ - protected void processTab() - { - moveCursorForward(8 - (cursorColumn % 8)); - } - - /** - * 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.

- * - * 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".

- */ - protected void processNewline() - { - int totalLines = text.getLineCount(); - int currentLineAbsolute = absoluteCursorLine(); - - if (currentLineAbsolute < totalLines - 1) - { - // The cursor is not on the bottommost line of text, so we move the cursor - // to the same column on the next line. - - // TODO: If we can verify that the next character is a carriage return, we - // can optimize out the insertion of spaces that moveCursorDown() will do. - - moveCursorDown(1); - } - else if (currentLineAbsolute == totalLines - 1) - { - // The cursor is on the bottommost line of text, so we append a newline - // character to the end of the terminal's text (creating a new line on the - // screen) and insert cursorColumn spaces. - - text.append("\n"); //$NON-NLS-1$ - text.append(generateString(' ', cursorColumn)); - text.setCaretOffset(text.getCharCount()); - - // We may have scrolled a line off the top of the screen, so check if we - // need to delete some of the the oldest lines in the scroll buffer. - - deleteTopmostLines(); - } - else - { - // This should _never_ happen. If it does happen, it is a bug in this - // algorithm. - - Logger.log("SHOULD NOT BE REACHED!"); //$NON-NLS-1$ - assert false; - } - } - - /** - * Process a Carriage Return (Ctrl-M). - */ - protected void processCarriageReturn() - { - // Move the cursor to the beginning of the current line. - - text.setCaretOffset(text.getOffsetAtLine(text.getLineAtOffset(text.getCaretOffset()))); - cursorColumn = 0; - } - - /** - * This method computes the width of the terminal in columns and its height in - * lines, then adjusts the width and height of the view's StyledText widget so that - * it displays an integral number of lines and columns of text. The adjustment is - * always to shrink the widget vertically or horizontally, because if the control - * were to grow, it would be clipped by the edges of the view window (i.e., the - * view window does not become larger to accommodate its contents becoming - * larger).

- * - * This method must be called immediately before each time text is written to the - * terminal so that we can properly line wrap text. Because it is called so - * frequently, it must be fast when there is no resizing to be done.

- */ - protected void adjustTerminalDimensions() - { - // Compute how many pixels we need to shrink the StyledText control vertically - // to make it display an integral number of lines of text. - - int linePixelHeight = text.getLineHeight(); - Point textWindowDimensions = text.getSize(); - int verticalPixelsToShrink = textWindowDimensions.y % linePixelHeight; - - // Compute the current height of the terminal in lines. - - heightInLines = textWindowDimensions.y / linePixelHeight; - - // Compute how many pixels we need to shrink the StyledText control to make - // it display an integral number of columns of text. We can only do this if we - // know the pixel width of a character in the font used by the StyledText - // widget. - - int horizontalPixelsToShrink = 0; - - if (characterPixelWidth == 0) - computeCharacterPixelWidth(); - - if (characterPixelWidth != 0) - { - horizontalPixelsToShrink = textWindowDimensions.x % characterPixelWidth; - - // The width of the StyledText widget that text.getSize() returns includes - // the space occupied by the vertical scrollbar, so we have to fudge this - // calculation (by subtracting 3 columns) to account for the presence of - // the scrollbar. Ugh. - - widthInColumns = textWindowDimensions.x / characterPixelWidth - 3; - } - - // If necessary, resize the text widget. - - if (verticalPixelsToShrink > 0 || horizontalPixelsToShrink > 0) - { - // Remove this class instance from being a ControlListener on the - // StyledText widget, because we are about to resize and move the widget, - // and we don't want this method to be recursively invoked. - - text.removeControlListener(this); - - // Shrink the StyledText control so that it displays an integral number - // of lines of text and an integral number of columns of text. - - textWindowDimensions.y -= verticalPixelsToShrink; - textWindowDimensions.x -= horizontalPixelsToShrink; - text.setSize(textWindowDimensions); - - // Move the StyledText control down by the same number of pixels that - // we just shrank it vertically and right by the same number of pixels that - // we just shrank it horizontally. This makes the padding appear to the - // left and top of the widget, which is more visually appealing. This is - // only necessary because there is no way to programmatically shrink the - // view itself. - - Point textLocation = text.getLocation(); - textLocation.y += verticalPixelsToShrink; - textLocation.x += horizontalPixelsToShrink; - text.setLocation(textLocation); - - // Restore this class instance as the ControlListener on the StyledText - // widget so we know when the user resizes the Terminal view. - - text.addControlListener(this); - - // Make sure the exposed portion of the Composite canvas behind the - // StyledText control matches the background color of the StyledText - // control. - - Color textBackground = text.getBackground(); - text.getParent().setBackground(textBackground); - - // Scroll the StyledText widget to the bottommost position. - - text.setSelectionRange(text.getCharCount(), 0); - text.showSelection(); - - // Tell the parent object to redraw itself. This erases any partial - // line of text that might be left visible where the parent object is - // now exposed. This call only happens if the size needed to be changed, - // so it should not cause any flicker. - - text.getParent().redraw(); - } - - // If we are in a TELNET connection and we know the dimensions of the terminal, - // we give the size information to the TELNET connection object so it can - // communicate it to the TELNET server. If we are in a serial connection, - // there is nothing we can do to tell the remote host about the size of the - // terminal. - - TelnetConnection telnetConnection = terminal.getTelnetConnection(); - - if (telnetConnection != null && telnetConnection.isConnected() && - telnetConnection.isRemoteTelnetServer() && - widthInColumns != 0 && heightInLines != 0) - { - telnetConnection.setTerminalSize(widthInColumns, heightInLines); - } - } - - /** - * This method computes the the pixel width of a character in the current font. - * The Font object representing the font in the Terminal view doesn't provide the - * pixel width of the characters (even for a fixed width font). Instead, we get - * the pixel coordinates of the upper left corner of the bounding boxes for two - * adjacent characters on the same line and subtract the X coordinate of one from - * the X coordinate of the other. Simple, no? - */ - protected void computeCharacterPixelWidth() - { - // We can't assume there is any text in the terminal, so make sure there's at - // least two characters. - - text.replaceTextRange(0, 0, " "); //$NON-NLS-1$ - - Point firstCharLocation = text.getLocationAtOffset(0); - Point secondCharLocation = text.getLocationAtOffset(1); - - characterPixelWidth = secondCharLocation.x - firstCharLocation.x; - - text.replaceTextRange(0, 3, ""); //$NON-NLS-1$ - } - - /** - * This method deletes as many of the topmost lines of text as needed to keep the - * total number of lines of text in the Terminal view less than or equal to the - * limit configured in the preferences. If no limit is configured, this method - * does nothing. - */ - protected void deleteTopmostLines() - { - Preferences preferences = TerminalPlugin.getDefault().getPluginPreferences(); - boolean bLimitOutput = preferences.getBoolean(TerminalConsts.TERMINAL_PREF_LIMITOUTPUT); - - if (!bLimitOutput) - return; - - // Compute the number of lines to delete, but don't do anything if there are - // fewer lines in the terminal than the height of the terminal in lines. - - int totalLineCount = text.getLineCount(); - - if (totalLineCount <= heightInLines) - return; - - int bufferLineLimit = preferences.getInt(TerminalConsts.TERMINAL_PREF_BUFFERLINES); - - // Don't allow the user to set the buffer line limit to less than the height of - // the terminal in lines. - - if (bufferLineLimit <= heightInLines) - bufferLineLimit = heightInLines + 1; - - int linesToDelete = totalLineCount - bufferLineLimit; - - // Delete the lines. A small optimization here: don't do anything unless - // there's at least 5 lines to delete. - - if (linesToDelete >= 5) - text.replaceTextRange(0, text.getOffsetAtLine(linesToDelete), ""); //$NON-NLS-1$ - } - - /** - * This method returns the absolute line number of the line containing the - * cursor. The very first line of text (even if it is scrolled off the screen) is - * absolute line number 0. - * - * @return The absolute line number of the line containing the cursor. - */ - protected int absoluteCursorLine() - { - return text.getLineAtOffset(text.getCaretOffset()); - } - - /** - * This method returns the relative line number of the line comtaining 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. - */ - protected int relativeCursorLine() - { - int totalLines = text.getLineCount(); - - if (totalLines <= heightInLines) - return text.getLineAtOffset(text.getCaretOffset()); - - return absoluteCursorLine() - totalLines + heightInLines; - } - - /** - * This method converts a visible line number (i.e., line 0 is the topmost visible - * line if the terminal is scrolled all the way down, and line number heightInLines - * - 1 is the bottommost visible line if the terminal is scrolled all the way down) - * to a line number as known to the StyledText widget. - */ - protected int absoluteLine(int visibleLineNumber) - { - int totalLines = text.getLineCount(); - - if (totalLines <= heightInLines) - return visibleLineNumber; - - return totalLines - heightInLines + visibleLineNumber; - } - - /** - * This method returns a String containing count ch characters. - * - * @return A String containing count ch characters. - */ - protected String generateString(char ch, int count) - { - char[] chars = new char[count]; - - for (int i = 0; i < chars.length; ++i) - chars[i] = ch; - - return new String(chars); - } - - /** - * This method moves the cursor to the specified line and column. Parameter - * targetLine 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. - */ - protected void moveCursor(int targetLine, int targetColumn) - { - // Don't allow out of range target line and column values. - - if (targetLine < 0) targetLine = 0; - if (targetLine >= heightInLines) targetLine = heightInLines - 1; - - if (targetColumn < 0) targetColumn = 0; - if (targetColumn >= widthInColumns) targetColumn = widthInColumns - 1; - - // First, find out if we need to append newlines to the end of the text. This - // is necessary if there are fewer total lines of text than visible screen - // lines and the target line is below the bottommost line of text. - - int totalLines = text.getLineCount(); - - if (totalLines < heightInLines && targetLine >= totalLines) - text.append(generateString('\n', heightInLines - totalLines)); - - // Next, compute the offset of the start of the target line. - - int targetLineStartOffset = text.getOffsetAtLine(absoluteLine(targetLine)); - - // Next, find how many characters are in the target line. Be careful not to - // index off the end of the StyledText widget. - - int nextLineNumber = absoluteLine(targetLine + 1); - int targetLineLength; - - if (nextLineNumber >= totalLines) - { - // The target line is the bottommost line of text. - - targetLineLength = text.getCharCount() - targetLineStartOffset; - } - else - { - // The target line is not the bottommost line of text, so compute its - // length by subtracting the start offset of the target line from the start - // offset of the following line. - - targetLineLength = text.getOffsetAtLine(nextLineNumber) - targetLineStartOffset - 1; - } - - // Find out if we can just move the cursor without having to insert spaces at - // the end of the target line. - - if (targetColumn >= targetLineLength) - { - // The target line is not long enough to just move the cursor, so we have - // to append spaces to it before positioning the cursor. - - int spacesToAppend = targetColumn - targetLineLength; - - text.replaceTextRange(targetLineStartOffset + targetLineLength, 0, - generateString(' ', spacesToAppend)); - } - - // Now position the cursor. - - text.setCaretOffset(targetLineStartOffset + targetColumn); - - cursorColumn = targetColumn; - } - - /** - * This method moves the cursor down lines lines, but won't move the cursor - * past the bottom of the screen. This method does not cause any scrolling. - */ - protected void moveCursorDown(int lines) - { - moveCursor(relativeCursorLine() + lines, cursorColumn); - } - - /** - * This method moves the cursor up lines lines, but won't move the cursor - * past the top of the screen. This method does not cause any scrolling. - */ - protected void moveCursorUp(int lines) - { - moveCursor(relativeCursorLine() - lines, cursorColumn); - } - - /** - * This method moves the cursor forward columns columns, but won't move the - * cursor past the right edge of the screen, nor will it move the cursor onto the - * next line. This method does not cause any scrolling. - */ - protected void moveCursorForward(int columnsToMove) - { - moveCursor(relativeCursorLine(), cursorColumn + columnsToMove); - } - - /** - * This method moves the cursor backward columnsToMove columns, but won't - * move the cursor past the left edge of the screen, nor will it move the cursor - * onto the previous line. This method does not cause any scrolling. - */ - protected void moveCursorBackward(int columnsToMove) - { - // We don't call moveCursor() here, because this is optimized for backward - // cursor motion on a single line. - - if (columnsToMove > cursorColumn) - columnsToMove = cursorColumn; - - text.setCaretOffset(text.getCaretOffset() - columnsToMove); - - cursorColumn -= columnsToMove; - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalView.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalView.java deleted file mode 100644 index b5117f7f294..00000000000 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalView.java +++ /dev/null @@ -1,1047 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2006 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: - * Wind River Systems, Inc. - initial implementation - * - *******************************************************************************/ - -package org.eclipse.tm.terminal; - -import org.eclipse.jface.action.ActionContributionItem; -import org.eclipse.jface.action.IMenuListener; -import org.eclipse.jface.action.IMenuManager; -import org.eclipse.jface.action.IToolBarManager; -import org.eclipse.jface.action.MenuManager; -import org.eclipse.jface.action.Separator; -import org.eclipse.jface.resource.FontRegistry; -import org.eclipse.jface.resource.JFaceResources; -import org.eclipse.jface.text.ITextSelection; -import org.eclipse.jface.util.IPropertyChangeListener; -import org.eclipse.jface.util.PropertyChangeEvent; -import org.eclipse.swt.custom.StyledText; -import org.eclipse.swt.dnd.Clipboard; -import org.eclipse.swt.dnd.TextTransfer; -import org.eclipse.swt.events.MenuEvent; -import org.eclipse.swt.events.MenuListener; -import org.eclipse.swt.graphics.Font; -import org.eclipse.swt.widgets.Composite; -import org.eclipse.swt.widgets.Menu; -import org.eclipse.ui.IActionBars; -import org.eclipse.ui.IPartListener; -import org.eclipse.ui.IViewSite; -import org.eclipse.ui.IWorkbench; -import org.eclipse.ui.IWorkbenchActionConstants; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.IWorkbenchPart; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.actions.ActionFactory; -import org.eclipse.ui.actions.RetargetAction; -import org.eclipse.ui.contexts.IContextActivation; -import org.eclipse.ui.contexts.IContextService; -import org.eclipse.ui.internal.WorkbenchWindow; -import org.eclipse.ui.part.ViewPart; - -public class TerminalView extends ViewPart implements TerminalTarget, TerminalConsts -{ - protected static final String m_SecondaryTerminalCountMutex = ""; //$NON-NLS-1$ - protected static int m_SecondaryTerminalCount = 0; - - protected TerminalCtrl m_ctlTerminal; - protected TerminalAction m_actionTerminalNewTerminal; - protected TerminalAction m_actionTerminalConnect; - protected TerminalAction m_actionTerminalDisconnect; - protected TerminalAction m_actionTerminalSettings; - protected TerminalAction m_actionEditCopy; - protected TerminalAction m_actionEditCut; - protected TerminalAction m_actionEditPaste; - protected TerminalAction m_actionEditClearAll; - protected TerminalAction m_actionEditSelectAll; - protected TerminalMenuHandlerEdit m_MenuHandlerEdit; - protected TerminalPropertyChangeHandler m_PropertyChangeHandler; - protected TerminalSettings m_TerminalSettings; - protected boolean m_bMenuAboutToShow; - /** Remember the item with which we contributed the shortcutt to unregister them again! */ - private IContextActivation fRememberedContextActivation; - - /** - * - */ - public TerminalView() - { - Logger.log("==============================================================="); //$NON-NLS-1$ - setupView(); - } - - // TerminalTarget interface - - /** - * - */ - public void execute(String strMsg,Object data) - { - if (strMsg.equals(ON_TERMINAL_FOCUS)) - { - onTerminalFocus(data); - } - else if (strMsg.equals(ON_TERMINAL_NEW_TERMINAL)) - { - onTerminalNewTerminal(data); - } - else if (strMsg.equals(ON_TERMINAL_CONNECT)) - { - onTerminalConnect(data); - } - else if (strMsg.equals(ON_UPDATE_TERMINAL_CONNECT)) - { - onUpdateTerminalConnect(data); - } - else if (strMsg.equals(ON_TERMINAL_CONNECTING)) - { - onTerminalConnecting(data); - } - else if (strMsg.equals(ON_TERMINAL_DISCONNECT)) - { - onTerminalDisconnect(data); - } - else if (strMsg.equals(ON_UPDATE_TERMINAL_DISCONNECT)) - { - onUpdateTerminalDisconnect(data); - } - else if (strMsg.equals(ON_TERMINAL_SETTINGS)) - { - onTerminalSettings(data); - } - else if (strMsg.equals(ON_UPDATE_TERMINAL_SETTINGS)) - { - onUpdateTerminalSettings(data); - } - else if (strMsg.equals(ON_TERMINAL_STATUS)) - { - onTerminalStatus(data); - } - else if (strMsg.equals(ON_TERMINAL_FONTCHANGED)) - { - onTerminalFontChanged(data); - } - else if (strMsg.equals(ON_EDIT_COPY)) - { - onEditCopy(data); - } - else if (strMsg.equals(ON_UPDATE_EDIT_COPY)) - { - onUpdateEditCopy(data); - } - else if (strMsg.equals(ON_EDIT_CUT)) - { - onEditCut(data); - } - else if (strMsg.equals(ON_UPDATE_EDIT_CUT)) - { - onUpdateEditCut(data); - } - else if (strMsg.equals(ON_EDIT_PASTE)) - { - onEditPaste(data); - } - else if (strMsg.equals(ON_UPDATE_EDIT_PASTE)) - { - onUpdateEditPaste(data); - } - else if (strMsg.equals(ON_EDIT_CLEARALL)) - { - onEditClearAll(data); - } - else if (strMsg.equals(ON_UPDATE_EDIT_CLEARALL)) - { - onUpdateEditClearAll(data); - } - else if (strMsg.equals(ON_EDIT_SELECTALL)) - { - onEditSelectAll(data); - } - else if (strMsg.equals(ON_UPDATE_EDIT_SELECTALL)) - { - onUpdateEditSelectAll(data); - } - else - { - } - } - - // Message handlers - - /** - * - */ - protected void onTerminalFocus(Object data) - { - m_ctlTerminal.setFocus(); - } - - /** - * Display a new Terminal view. This method is called when the user clicks the New - * Terminal button in any Terminal view's toolbar. - */ - protected void onTerminalNewTerminal(Object data) - { - Logger.log("creating new Terminal instance."); //$NON-NLS-1$ - - try - { - // The second argument to showView() is a unique String identifying the - // secondary view instance. If it ever matches a previously used secondary - // view identifier, then this call will not create a new Terminal view, - // which is undesireable. Therefore, we append the current time in - // milliseconds to the secondary view identifier to ensure it is always - // unique. This code runs only when the user clicks the New Terminal - // button, so there is no risk that this code will run twice in a single - // millisecond. - - getSite().getPage().showView("org.eclipse.tm.terminal.TerminalView",//$NON-NLS-1$ - "SecondaryTerminal" + System.currentTimeMillis(), //$NON-NLS-1$ - IWorkbenchPage.VIEW_ACTIVATE); - } - catch (PartInitException ex) - { - Logger.logException(ex); - } - } - - /** - * - */ - protected void onTerminalConnect(Object data) - { - if (m_ctlTerminal.isConnected()) - return; - - m_ctlTerminal.connectTerminal(m_TerminalSettings); - - execute(ON_UPDATE_TERMINAL_CONNECT,null); - execute(ON_UPDATE_TERMINAL_DISCONNECT,null); - execute(ON_UPDATE_TERMINAL_SETTINGS,null); - } - - /** - * - */ - protected void onTerminalConnecting(Object data) - { - execute(ON_UPDATE_TERMINAL_CONNECT,null); - execute(ON_UPDATE_TERMINAL_DISCONNECT,null); - execute(ON_UPDATE_TERMINAL_SETTINGS,null); - } - - /** - * - */ - protected void onUpdateTerminalConnect(Object data) - { - boolean bEnabled; - - bEnabled = ((!m_ctlTerminal.isConnecting()) && - (!m_ctlTerminal.isConnected())); - - m_actionTerminalConnect.setEnabled(bEnabled); - } - - /** - * - */ - protected void onTerminalDisconnect(Object data) - { - if ((!m_ctlTerminal.isConnecting()) && - (!m_ctlTerminal.isConnected())) - { - execute(ON_TERMINAL_STATUS, null); - execute(ON_UPDATE_TERMINAL_CONNECT, null); - execute(ON_UPDATE_TERMINAL_DISCONNECT, null); - execute(ON_UPDATE_TERMINAL_SETTINGS, null); - return; - } - - m_ctlTerminal.disconnectTerminal(); - - execute(ON_UPDATE_TERMINAL_CONNECT,null); - execute(ON_UPDATE_TERMINAL_DISCONNECT,null); - execute(ON_UPDATE_TERMINAL_SETTINGS,null); - } - - /** - * - */ - protected void onUpdateTerminalDisconnect(Object data) - { - boolean bEnabled; - - bEnabled = ((m_ctlTerminal.isConnecting()) || - (m_ctlTerminal.isConnected())); - - m_actionTerminalDisconnect.setEnabled(bEnabled); - } - - /** - * - */ - protected void onTerminalSettings(Object data) - { - TerminalSettingsDlg dlgTerminalSettings; - int nStatus; - - // When the settings dialog is opened, load the Terminal settings from the - // persistent settings. - - m_TerminalSettings.importSettings(getPartName()); - - dlgTerminalSettings = new TerminalSettingsDlg(getViewSite().getShell()); - dlgTerminalSettings.loadSettings(m_TerminalSettings); - - Logger.log("opening Settings dialog."); //$NON-NLS-1$ - - nStatus = dlgTerminalSettings.open(); - - if (nStatus == TerminalConsts.TERMINAL_ID_CANCEL) - { - Logger.log("Settings dialog cancelled."); //$NON-NLS-1$ - return; - } - - Logger.log("Settings dialog OK'ed."); //$NON-NLS-1$ - - // When the settings dialog is closed, we persist the Terminal settings. - - m_TerminalSettings.exportSettings(getPartName()); - - execute(ON_TERMINAL_CONNECT,null); - } - - /** - * - */ - protected void onUpdateTerminalSettings(Object data) - { - boolean bEnabled; - - bEnabled = ((!m_ctlTerminal.isConnecting()) && - (!m_ctlTerminal.isConnected())); - - m_actionTerminalSettings.setEnabled(bEnabled); - } - - /** - * - */ - protected void onTerminalStatus(Object data) - { - String strConnType; - String strConnected; - String strSerialPort; - String strBaudRate; - String strDataBits; - String strStopBits; - String strParity; - String strFlowControl; - String strHost; - String strNetworkPort; - String strText; - String strTitle; - - if (m_ctlTerminal.isDisposed()) - return; - - if (data != null) - { - // When parameter 'data' is not null, it is a String containing text to - // display in the view's content description line. This is used by class - // TerminalText when it processes an ANSI OSC escape sequence that commands - // the terminal to display text in its title bar. - - strTitle = (String)data; - } - else - { - // When parameter 'data' is null, we construct a descriptive string to - // display in the content description line. - - if (m_ctlTerminal.isConnecting()) - { - strConnected = "CONNECTING..."; //$NON-NLS-1$ - } - else if (m_ctlTerminal.isOpened()) - { - strConnected = "OPENED"; //$NON-NLS-1$ - } - else if (m_ctlTerminal.isConnected()) - { - strConnected = "CONNECTED"; //$NON-NLS-1$ - } - else - { - strConnected = "CLOSED"; //$NON-NLS-1$ - } - - strConnType = m_TerminalSettings.getConnType(); - if (strConnType.equals(TERMINAL_CONNTYPE_SERIAL)) - { - strSerialPort = m_TerminalSettings.getSerialPort(); - strBaudRate = m_TerminalSettings.getBaudRate(); - strDataBits = m_TerminalSettings.getDataBits(); - strStopBits = m_TerminalSettings.getStopBits(); - strParity = m_TerminalSettings.getParity(); - strFlowControl = m_TerminalSettings.getFlowControl(); - strText = " (" + //$NON-NLS-1$ - strSerialPort + - ", " + //$NON-NLS-1$ - strBaudRate + - ", " + //$NON-NLS-1$ - strDataBits + - ", " + //$NON-NLS-1$ - strStopBits + - ", " + //$NON-NLS-1$ - strParity + - ", " + //$NON-NLS-1$ - strFlowControl + - " - " + //$NON-NLS-1$ - strConnected + - ")"; //$NON-NLS-1$ - } - else if (strConnType.equals(TERMINAL_CONNTYPE_NETWORK)) - { - strHost = m_TerminalSettings.getHost(); - strNetworkPort = m_TerminalSettings.getNetworkPort(); - strText = " (" + //$NON-NLS-1$ - strHost + - ":" + //$NON-NLS-1$ - strNetworkPort + - " - " + //$NON-NLS-1$ - strConnected + - ")"; //$NON-NLS-1$ - } - else - { - strText = ""; //$NON-NLS-1$ - } - - strTitle = TERMINAL_PROP_TITLE + strText; - } - - setContentDescription(strTitle); - getViewSite().getActionBars().getStatusLineManager().setMessage(strTitle); - } - - /** - * - */ - protected void onTerminalFontChanged(Object data) - { - StyledText ctlText; - Font font; - - ctlText = m_ctlTerminal.getTextWidget(); - font = JFaceResources.getFont(TERMINAL_FONT_DEFINITION); - ctlText.setFont(font); - - // Tell the TerminalCtrl singleton that the font has changed. - - m_ctlTerminal.onFontChanged(); - } - - /** - * - */ - protected void onEditCopy(Object data) - { - ITextSelection selection; - String strText; - boolean bEnabled; - - selection = m_ctlTerminal.getSelection(); - strText = selection.getText(); - bEnabled = !strText.equals(""); //$NON-NLS-1$ - - if (bEnabled) - { - m_ctlTerminal.copy(); - } - else - { - m_ctlTerminal.sendKey('\u0003'); - } - } - - /** - * - */ - protected void onUpdateEditCopy(Object data) - { - ITextSelection selection; - String strText; - boolean bEnabled; - - if (m_bMenuAboutToShow) - { - selection = m_ctlTerminal.getSelection(); - strText = selection.getText(); - bEnabled = !strText.equals(""); //$NON-NLS-1$ - } - else - { - bEnabled = true; - } - - m_actionEditCopy.setEnabled(bEnabled); - } - - /** - * - */ - protected void onEditCut(Object data) - { - m_ctlTerminal.sendKey('\u0018'); - } - - /** - * - */ - protected void onUpdateEditCut(Object data) - { - boolean bEnabled; - - bEnabled = !m_bMenuAboutToShow; - m_actionEditCut.setEnabled(bEnabled); - } - - /** - * - */ - protected void onEditPaste(Object data) - { - m_ctlTerminal.paste(); - } - - /** - * - */ - protected void onUpdateEditPaste(Object data) - { - Clipboard clipboard; - TextTransfer textTransfer; - String strText; - boolean bConnected; - boolean bEnabled; - - clipboard = m_ctlTerminal.getClipboard(); - textTransfer = TextTransfer.getInstance(); - strText = (String)clipboard.getContents(textTransfer); - bConnected = m_ctlTerminal.isConnected(); - - bEnabled = ((strText != null) && - (!strText.equals("")) && //$NON-NLS-1$ - (bConnected)); - - m_actionEditPaste.setEnabled(bEnabled); - } - - /** - * - */ - protected void onEditClearAll(Object data) - { - m_ctlTerminal.clearTerminal(); - } - - /** - * - */ - protected void onUpdateEditClearAll(Object data) - { - boolean bEnabled; - - bEnabled = !m_ctlTerminal.isEmpty(); - m_actionEditClearAll.setEnabled(bEnabled); - } - - /** - * - */ - protected void onEditSelectAll(Object data) - { - m_ctlTerminal.selectAll(); - } - - /** - * - */ - protected void onUpdateEditSelectAll(Object data) - { - boolean bEnabled; - - bEnabled = !m_ctlTerminal.isEmpty(); - m_actionEditSelectAll.setEnabled(bEnabled); - } - - // ViewPart interface - - /** - * - */ - public void createPartControl(Composite wndParent) - { - // Bind plugin.xml key bindings to this plugin. Overrides global Ctrl-W key - // sequence. - - /** Activate the sy context allowing shortcuts like F3(open declaration) in the view */ - IContextService ctxtService = (IContextService)getSite().getService(IContextService.class); - fRememberedContextActivation = ctxtService.activateContext("org.eclipse.tm.terminal.TerminalPreferencePage"); //$NON-NLS-1$ - - setupControls(wndParent); - setupActions(); - setupMenus(); - setupToolBars(); - setupLocalMenus(); - setupLocalToolBars(); - setupContextMenus(); - setupListeners(wndParent); - - synchronized (m_SecondaryTerminalCountMutex) - { - setPartName(TERMINAL_PROP_TITLE + " " + m_SecondaryTerminalCount++); //$NON-NLS-1$ - } - - execute(ON_TERMINAL_STATUS,null); - } - - /** - * - */ - public void dispose() - { - Logger.log("entered."); //$NON-NLS-1$ - - setPartName("Terminal"); //$NON-NLS-1$ - - TerminalPlugin plugin; - FontRegistry fontRegistry; - IWorkbench workbench; - WorkbenchWindow workbenchWindow; - MenuManager menuMgr; - Menu menu; - - /** The context (for short cuts) was set above, now unset it again */ - if (fRememberedContextActivation != null) { - IContextService ctxService = (IContextService)getSite().getService(IContextService.class); - ctxService.deactivateContext(fRememberedContextActivation); - fRememberedContextActivation = null; - } - - fontRegistry = JFaceResources.getFontRegistry(); - plugin = TerminalPlugin.getDefault(); - workbench = plugin.getWorkbench(); - workbenchWindow = (WorkbenchWindow) workbench.getActiveWorkbenchWindow(); - menuMgr = workbenchWindow.getMenuManager(); - menuMgr = (MenuManager) menuMgr.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); - menu = menuMgr.getMenu(); - - fontRegistry.removeListener(m_PropertyChangeHandler); - menuMgr.removeMenuListener(m_MenuHandlerEdit); - - if (menu != null) - menu.removeMenuListener(m_MenuHandlerEdit); - - m_ctlTerminal.disposeTerminal(); - } - - /** - * Passing the focus request to the viewer's control. - */ - public void setFocus() - { - execute(ON_TERMINAL_FOCUS,null); - } - - // Operations - - /** - * - */ - protected void setupView() - { - m_TerminalSettings = new TerminalSettings(getPartName()); - m_bMenuAboutToShow = false; - } - - /** - * This method creates the top-level control for the Terminal view. - */ - protected void setupControls(Composite wndParent) - { - try - { - m_ctlTerminal = new TerminalCtrl(this, wndParent); - } - catch (Exception ex) - { - Logger.logException(ex); - } - } - - /** - * - */ - protected void setupActions() - { - IViewSite viewSite; - IActionBars actionBars; - - viewSite = getViewSite(); - actionBars = viewSite.getActionBars(); - m_actionTerminalNewTerminal = new TerminalActionNewTerminal(this); - m_actionTerminalConnect = new TerminalActionConnect(this); - m_actionTerminalDisconnect = new TerminalActionDisconnect(this); - m_actionTerminalSettings = new TerminalActionSettings(this); - m_actionEditCopy = new TerminalActionCopy(this); - m_actionEditCut = new TerminalActionCut(this); - m_actionEditPaste = new TerminalActionPaste(this); - m_actionEditClearAll = new TerminalActionClearAll(this); - m_actionEditSelectAll = new TerminalActionSelectAll(this); - - actionBars.setGlobalActionHandler(ActionFactory.COPY.getId(), - m_actionEditCopy); - - actionBars.setGlobalActionHandler(ActionFactory.CUT.getId(), - m_actionEditCut); - - actionBars.setGlobalActionHandler(ActionFactory.PASTE.getId(), - m_actionEditPaste); - - actionBars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), - m_actionEditSelectAll); - } - - /** - * - */ - protected void setupMenus() - { - TerminalPlugin plugin; - IWorkbench workbench; - WorkbenchWindow workbenchWindow; - MenuManager menuMgr; - Menu menu; - - m_MenuHandlerEdit = new TerminalMenuHandlerEdit(); - plugin = TerminalPlugin.getDefault(); - workbench = plugin.getWorkbench(); - workbenchWindow = (WorkbenchWindow) workbench.getActiveWorkbenchWindow(); - menuMgr = workbenchWindow.getMenuManager(); - menuMgr = (MenuManager)menuMgr.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); - menu = menuMgr.getMenu(); - - menuMgr.addMenuListener(m_MenuHandlerEdit); - menu.addMenuListener(m_MenuHandlerEdit); - } - - /** - * - */ - protected void setupToolBars() - { - } - - /** - * - */ - protected void setupLocalMenus() - { - } - - /** - * - */ - protected void setupLocalToolBars() - { - IViewSite viewSite; - IActionBars actionBars; - IToolBarManager toolBarMgr; - - viewSite = getViewSite(); - actionBars = viewSite.getActionBars(); - toolBarMgr = actionBars.getToolBarManager(); - - toolBarMgr.add(m_actionTerminalNewTerminal); - toolBarMgr.add(m_actionTerminalConnect); - toolBarMgr.add(m_actionTerminalDisconnect); - toolBarMgr.add(m_actionTerminalSettings); - } - - /** - * - */ - protected void setupContextMenus() - { - StyledText ctlText; - MenuManager menuMgr; - Menu menu; - TerminalContextMenuHandler contextMenuHandler; - - ctlText = m_ctlTerminal.getTextWidget(); - menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$ - menu = menuMgr.createContextMenu(ctlText); - contextMenuHandler = new TerminalContextMenuHandler(); - - ctlText.setMenu(menu); - menuMgr.setRemoveAllWhenShown(true); - menuMgr.addMenuListener(contextMenuHandler); - menu.addMenuListener(contextMenuHandler); - } - - /** - * - */ - protected void loadContextMenus(IMenuManager menuMgr) - { - menuMgr.add(m_actionEditCopy); - menuMgr.add(m_actionEditPaste); - menuMgr.add(new Separator()); - menuMgr.add(m_actionEditClearAll); - menuMgr.add(m_actionEditSelectAll); - - // Other plug-ins can contribute there actions here - menuMgr.add(new Separator("Additions")); //$NON-NLS-1$ - } - - /** - * - */ - protected void setupListeners(Composite wndParent) - { - getViewSite().getPage().addPartListener(new IPartListener() { - public void partClosed(IWorkbenchPart part) - { - if (part instanceof TerminalView) - part.dispose(); - } - - public void partActivated(IWorkbenchPart part) { } - public void partBroughtToTop(IWorkbenchPart part) { } - public void partDeactivated(IWorkbenchPart part) { } - public void partOpened(IWorkbenchPart part) { } - }); - - FontRegistry fontRegistry = JFaceResources.getFontRegistry(); - m_PropertyChangeHandler = new TerminalPropertyChangeHandler(); - fontRegistry.addListener(m_PropertyChangeHandler); - } - - // Inner classes - - /** - * - */ - protected class TerminalMenuHandlerEdit - implements MenuListener, - IMenuListener - { - /** - * - */ - protected String m_strActionDefinitionIdCopy; - protected String m_strActionDefinitionIdPaste; - protected String m_strActionDefinitionIdSelectAll; - - protected int m_nAcceleratorCopy; - protected int m_nAcceleratorPaste; - protected int m_nAcceleratorSelectAll; - - /** - * - */ - protected TerminalMenuHandlerEdit() - { - super(); - - m_strActionDefinitionIdCopy = ""; //$NON-NLS-1$ - m_strActionDefinitionIdPaste = ""; //$NON-NLS-1$ - m_strActionDefinitionIdSelectAll = ""; //$NON-NLS-1$ - - m_nAcceleratorCopy = 0; - m_nAcceleratorPaste = 0; - m_nAcceleratorSelectAll = 0; - } - - // IMenuListener interface - - /** - * - */ - public void menuAboutToShow(IMenuManager menuMgr) - { - ActionContributionItem item; - RetargetAction action; - - m_bMenuAboutToShow = true; - execute(ON_UPDATE_EDIT_COPY,null); - execute(ON_UPDATE_EDIT_CUT,null); - execute(ON_UPDATE_EDIT_PASTE,null); - execute(ON_UPDATE_EDIT_SELECTALL,null); - - item = (ActionContributionItem)menuMgr.find(ActionFactory.COPY.getId()); - action = (RetargetAction) item.getAction(); - m_strActionDefinitionIdCopy = action.getActionDefinitionId(); - m_nAcceleratorCopy = action.getAccelerator(); - action.setActionDefinitionId(null); - action.enableAccelerator(false); - item.update(); - - item = (ActionContributionItem)menuMgr.find(ActionFactory.PASTE.getId()); - action = (RetargetAction) item.getAction(); - m_strActionDefinitionIdPaste = action.getActionDefinitionId(); - m_nAcceleratorPaste = action.getAccelerator(); - action.setActionDefinitionId(null); - action.enableAccelerator(false); - item.update(); - - item = (ActionContributionItem)menuMgr.find(ActionFactory.SELECT_ALL.getId()); - action = (RetargetAction) item.getAction(); - m_strActionDefinitionIdSelectAll = action.getActionDefinitionId(); - m_nAcceleratorSelectAll = action.getAccelerator(); - action.setActionDefinitionId(null); - action.enableAccelerator(false); - item.update(); - } - - // MenuListener interface - - /** - * - */ - public void menuShown(MenuEvent event) - { - } - - /** - * - */ - public void menuHidden(MenuEvent event) - { - TerminalPlugin plugin; - IWorkbench workbench; - WorkbenchWindow workbenchWindow; - MenuManager menuMgr; - ActionContributionItem item; - RetargetAction action; - - m_bMenuAboutToShow = false; - execute(ON_UPDATE_EDIT_COPY,null); - execute(ON_UPDATE_EDIT_CUT,null); - - plugin = TerminalPlugin.getDefault(); - workbench = plugin.getWorkbench(); - workbenchWindow = (WorkbenchWindow) workbench.getActiveWorkbenchWindow(); - menuMgr = workbenchWindow.getMenuManager(); - menuMgr = (MenuManager) menuMgr.findMenuUsingPath(IWorkbenchActionConstants.M_EDIT); - - item = (ActionContributionItem) menuMgr.find(ActionFactory.COPY.getId()); - action = (RetargetAction) item.getAction(); - action.setActionDefinitionId(m_strActionDefinitionIdCopy); - action.setAccelerator(m_nAcceleratorCopy); - action.enableAccelerator(true); - item.update(); - - item = (ActionContributionItem) menuMgr.find(ActionFactory.PASTE.getId()); - action = (RetargetAction) item.getAction(); - action.setActionDefinitionId(m_strActionDefinitionIdPaste); - action.setAccelerator(m_nAcceleratorPaste); - action.enableAccelerator(true); - item.update(); - - item = (ActionContributionItem) menuMgr.find(ActionFactory.SELECT_ALL.getId()); - action = (RetargetAction) item.getAction(); - action.setActionDefinitionId(m_strActionDefinitionIdSelectAll); - action.setAccelerator(m_nAcceleratorSelectAll); - action.enableAccelerator(true); - item.update(); - } - } - - /** - * - */ - protected class TerminalContextMenuHandler - implements MenuListener, IMenuListener - { - /** - * - */ - protected TerminalContextMenuHandler() - { - super(); - } - - // MenuListener interface - - /** - * - */ - public void menuHidden(MenuEvent event) - { - m_bMenuAboutToShow = false; - execute(ON_UPDATE_EDIT_COPY,null); - } - - public void menuShown(MenuEvent e) - { - } - - // IMenuListener interface - - /** - * - */ - public void menuAboutToShow(IMenuManager menuMgr) - { - m_bMenuAboutToShow = true; - execute(ON_UPDATE_EDIT_COPY,null); - execute(ON_UPDATE_EDIT_PASTE,null); - execute(ON_UPDATE_EDIT_CLEARALL,null); - execute(ON_UPDATE_EDIT_SELECTALL,null); - - loadContextMenus(menuMgr); - } - } - - /** - * - */ - protected class TerminalPropertyChangeHandler implements IPropertyChangeListener - { - /** - * - */ - protected TerminalPropertyChangeHandler() - { - super(); - } - - // IPropertyChangeListener interface - - public void propertyChange(PropertyChangeEvent event) - { - String strProperty; - - strProperty = event.getProperty(); - if (strProperty.equals(TERMINAL_FONT_DEFINITION)) - { - execute(ON_TERMINAL_FONTCHANGED,event); - } - else - { - } - } - } -} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalListener.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalListener.java new file mode 100644 index 00000000000..972c2a7068c --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalListener.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.control; + +import org.eclipse.tm.terminal.TerminalState; + + +/** + * Provided by a view implementation. + * @author Michael Scharf + * + */ +public interface ITerminalListener { + /** + * Called when the state of the connection has changed. + * @param state + */ + void setState(TerminalState state); + /** + * Set the title of the terminal. + * @param title + */ + void setTerminalTitle(String title); +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalViewControl.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalViewControl.java new file mode 100644 index 00000000000..5a8b4f6e5e8 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/ITerminalViewControl.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.control; + +import org.eclipse.swt.custom.StyledText; +import org.eclipse.tm.terminal.TerminalState; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.tm.terminal.ITerminalConnector; + +/** + * @author Michael Scharf + * + */ +public interface ITerminalViewControl { + boolean isEmpty(); + void onFontChanged(); + StyledText getCtlText(); + boolean isDisposed(); + void selectAll(); + void clearTerminal(); + void copy(); + void paste(); + String getSelection(); + TerminalState getState(); + Clipboard getClipboard(); + void disconnectTerminal(); + void disposeTerminal(); + String getStatusString(String status); + ITerminalConnector[] getConnectors(); + void setFocus(); + ITerminalConnector getTerminalConnection(); + void setConnector(ITerminalConnector connector); + void connectTerminal(); + void sendKey(char arg0); + boolean isConnected(); + +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/TerminalViewControlFactory.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/TerminalViewControlFactory.java new file mode 100644 index 00000000000..808ce9e9381 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/control/TerminalViewControlFactory.java @@ -0,0 +1,22 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.control; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.internal.control.TerminalControl; + +public class TerminalViewControlFactory { + public static ITerminalViewControl makeControl(ITerminalListener target, Composite wndParent, ITerminalConnector[] connectors) { + return new TerminalControl(target, wndParent, connectors); + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/ITerminalControlForText.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/ITerminalControlForText.java new file mode 100644 index 00000000000..36f542cd92e --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/ITerminalControlForText.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ +package org.eclipse.tm.terminal.internal.control; + +import java.io.OutputStream; + +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.TerminalState; + +/** + * need a better name! + * @author Michael Scharf + * + */ +public interface ITerminalControlForText { + + TerminalState getState(); + void setState(TerminalState state); + void setTerminalTitle(String title); + + ITerminalConnector getTerminalConnection(); + + void disconnectTerminal(); + + OutputStream getOutputStream(); + +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalControl.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalControl.java new file mode 100644 index 00000000000..99c34f68402 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalControl.java @@ -0,0 +1,807 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.control; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.SocketException; + +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.text.ConfigurableLineTracker; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.ITextSelection; +import org.eclipse.jface.text.TextViewer; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.custom.VerifyKeyListener; +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.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.VerifyEvent; +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.Shell; +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.keys.IBindingService; +import org.eclipse.tm.terminal.control.ITerminalListener; +import org.eclipse.tm.terminal.control.ITerminalViewControl; + +/** + * + * 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 + */ +public class TerminalControl 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 TerminalText fTerminalText; + + private Display fDisplay; + private StyledText fCtlText; + private TextViewer fViewer; + private Composite fWndParent; + private Clipboard fClipboard; + private TerminalModifyListener fModifyListener; + private KeyListener fKeyHandler; + private ITerminalListener fTerminalListener; + private String fMsg = ""; //$NON-NLS-1$ + private VerifyKeyListener fVerifyKeyListener; + private FocusListener fFocusListener; + private ITerminalConnector fConnector; + private final ITerminalConnector[] fConnectors; + + private volatile TerminalState fState; + + public TerminalControl(ITerminalListener target, Composite wndParent, ITerminalConnector[] connectors) { + fConnectors=connectors; + fTerminalListener=target; + fWndParent = wndParent; + + setTerminalText(new TerminalText(this)); + + setupTerminal(); + } + + public ITerminalConnector[] getConnectors() { + return fConnectors; + } + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#copy() + */ + public void copy() { + getCtlText().copy(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#paste() + */ + public void paste() { + TextTransfer textTransfer = TextTransfer.getInstance(); + String strText = (String) fClipboard.getContents(textTransfer); + if (strText == null) + return; + for (int i = 0; i < strText.length(); i++) { + sendChar(strText.charAt(i), false); + } +// 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(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#selectAll() + */ + public void selectAll() { + getCtlText().selectAll(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.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.terminal.ITerminalControl#clearTerminal() + */ + public void clearTerminal() { + // The TerminalText object does all text manipulation. + + getTerminalText().clearTerminal(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#getClipboard() + */ + public Clipboard getClipboard() { + return fClipboard; + } + + /** + * @return non null selection + */ + public String getSelection() { + String txt= ((ITextSelection) fViewer.getSelection()).getText(); + if(txt==null) + txt=""; //$NON-NLS-1$ + return txt; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#setFocus() + */ + public void setFocus() { + getCtlText().setFocus(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#isEmpty() + */ + public boolean isEmpty() { + return (getCtlText().getCharCount() == 0); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#isDisposed() + */ + public boolean isDisposed() { + return getCtlText().isDisposed(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#isConnected() + */ + public boolean isConnected() { + return fState==TerminalState.CONNECTED; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.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(fConnector==null) + return; + fConnector.connect(this); + waitForConnect(); + } + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#disconnectTerminal() + */ + public void disconnectTerminal() { + Logger.log("entered."); //$NON-NLS-1$ + + if (getState()==TerminalState.CLOSED) { + return; + } + if(fConnector!=null) { + fConnector.disconnect(); +// fConnector=null; + } + } + // 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$ + { + String strTitle = TerminalMessages.TerminalError; + MessageDialog.openError( getShell(), strTitle, getMsg()); + + disconnectTerminal(); + return; + } + + getCtlText().setFocus(); + } + + 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 strTitle = TerminalMessages.TerminalError; + String strMsg = TerminalMessages.SocketError + + "!\n" + socketException.getMessage(); //$NON-NLS-1$ + + MessageDialog.openError(getShell(), strTitle, strMsg); + Logger.logException(socketException); + + disconnectTerminal(); + } catch (IOException ioException) { + displayTextInTerminal(ioException.getMessage()); + + String strTitle = TerminalMessages.TerminalError; + String strMsg = TerminalMessages.IOError + "!\n" + ioException.getMessage(); //$NON-NLS-1$ + + MessageDialog.openError(getShell(), strTitle, strMsg); + 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 strTitle = TerminalMessages.TerminalError; + String strMsg = TerminalMessages.SocketError + + "!\n" + socketException.getMessage(); //$NON-NLS-1$ + + MessageDialog.openError(getShell(), strTitle, strMsg); + Logger.logException(socketException); + + disconnectTerminal(); + } catch (IOException ioException) { + Logger.logException(ioException); + + displayTextInTerminal(ioException.getMessage()); + + String strTitle = TerminalMessages.TerminalError; + String strMsg = TerminalMessages.IOError + "!\n" + ioException.getMessage(); //$NON-NLS-1$ + + MessageDialog.openError(getShell(), strTitle, strMsg); + Logger.logException(ioException); + + disconnectTerminal(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#setupTerminal() + */ + public void setupTerminal() { + fState=TerminalState.CLOSED; + setupControls(); + setupListeners(); + setupHelp(fWndParent, TerminalPlugin.HELP_VIEW); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#onFontChanged() + */ + public void onFontChanged() { + getTerminalText().fontChanged(); + } + + protected void setupControls() { + // 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(). + + fViewer = new TextViewer(fWndParent, SWT.V_SCROLL); + setCtlText(fViewer.getTextWidget()); + + fDisplay = getCtlText().getDisplay(); + fClipboard = new Clipboard(fDisplay); + fViewer.setDocument(new TerminalDocument()); + getCtlText().setFont(JFaceResources.getTextFont()); + } + + protected void setupListeners() { + fKeyHandler = new TerminalKeyHandler(); + fModifyListener = new TerminalModifyListener(); + fVerifyKeyListener = new TerminalVerifyKeyListener(); + fFocusListener = new TerminalFocusListener(); + + getCtlText().addVerifyKeyListener(fVerifyKeyListener); + getCtlText().addKeyListener(fKeyHandler); + getCtlText().addModifyListener(fModifyListener); + getCtlText().addVerifyKeyListener(fVerifyKeyListener); + 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.terminal.ITerminalControl#displayTextInTerminal(java.lang.String) + */ + public void displayTextInTerminal(String text) { + writeToTerminal(text+"\r\n"); //$NON-NLS-1$ + } + + public void writeToTerminal(String txt) { + + // Do _not_ use asyncExec() here. Class TerminalText requires that + // its run() and setNewText() methods be called in strictly + // alternating order. If we were to call asyncExec() here, this + // loop might race around and call setNewText() twice in a row, + // which would lose data. + getTerminalText().setNewText(new StringBuffer(txt)); + if(Display.getDefault().getThread()==Thread.currentThread()) + getTerminalText().run(); + else + fDisplay.syncExec(getTerminalText()); + + } + + protected boolean isLogCharEnabled() { + return TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_CHAR); + } + protected boolean isLogBufferSizeEnabled() { + return TerminalPlugin + .isOptionEnabled(Logger.TRACE_DEBUG_LOG_BUFFER_SIZE); + } + + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#getInputStream() + */ + public InputStream getInputStream() { + if(fConnector!=null) + return fConnector.getInputStream(); + return null; + } + + public OutputStream getOutputStream() { + if(fConnector!=null) + return fConnector.getOutputStream(); + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#setMsg(java.lang.String) + */ + public void setMsg(String msg) { + fMsg = msg; + } + + public String getMsg() { + return fMsg; + } + + void setCtlText(StyledText ctlText) { + fCtlText = ctlText; + fTerminalText.setStyledText(ctlText); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#getCtlText() + */ + public StyledText getCtlText() { + return fCtlText; + } + + void setTerminalText(TerminalText terminalText) { + fTerminalText = terminalText; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.ITerminalControl#getTerminalText() + */ + public TerminalText getTerminalText() { + return fTerminalText; + } + + /** + */ + public ITerminalConnector getTerminalConnection() { + return fConnector; + } + + protected class TerminalModifyListener implements ModifyListener { + public void modifyText(ModifyEvent e) { + if (e.getSource() instanceof StyledText) { + StyledText text = (StyledText) e.getSource(); + text.setSelection(text.getText().length()); + } + } + } + + 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 TerminalVerifyKeyListener implements VerifyKeyListener { + public void verifyKey(VerifyEvent event) { + // We set event.doit to false to prevent keyboard input from locally + // modifying the contents of the StyledText widget. The only text we + // display is text received from the remote endpoint. This also prevents + // the caret from moving locally when the user presses an arrow key or the + // PageUp or PageDown keys. For some reason, doing this in + // TerminalKeyHandler.keyPressed() does not work, hence the need for this + // class. + + event.doit = false; + } + } + 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 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' && getTerminalConnection() != null + && isConnected() + && getTerminalConnection().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 (getTerminalConnection() == null + || getTerminalConnection().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()); + } + + } + + protected class TerminalDocument extends Document { + protected TerminalDocument() { + setLineTracker(new ConfigurableLineTracker(LINE_DELIMITERS)); + } + } + + 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 getStatusString(String strConnected) { + if(fConnector!=null) + return fConnector.getStatusString(strConnected); + return strConnected; + } + + public void setConnector(ITerminalConnector connector) { + fConnector=connector; + + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalTarget.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.java similarity index 62% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalTarget.java rename to org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.java index 4e6bcd9bca4..f8a1a6f16fe 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TerminalTarget.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.java @@ -9,11 +9,16 @@ * Wind River Systems, Inc. - initial implementation * *******************************************************************************/ +package org.eclipse.tm.terminal.internal.control; -package org.eclipse.tm.terminal; +import org.eclipse.osgi.util.NLS; +public class TerminalMessages extends NLS { + static { + NLS.initializeMessages(TerminalMessages.class.getName(), TerminalMessages.class); + } + + public static String TerminalError; + public static String SocketError; + public static String IOError; -public interface TerminalTarget - extends TerminalMsg -{ - public void execute(String strMsg,Object data); } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.properties b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.properties new file mode 100644 index 00000000000..ceea6affc96 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalMessages.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2006 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: +# Wind River Systems, Inc. - initial implementation +# +############################################################################### +TerminalError = Terminal Error +SocketError = Socket Error +IOError = IO Error diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalPlugin.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalPlugin.java new file mode 100644 index 00000000000..6acd3c46a4c --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalPlugin.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.control; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.ui.plugin.AbstractUIPlugin; + +public class TerminalPlugin extends AbstractUIPlugin { + protected static TerminalPlugin fDefault; + public static final String PLUGIN_HOME = "org.eclipse.tm.terminal"; //$NON-NLS-1$ + public static final String HELP_VIEW = PLUGIN_HOME + ".terminal_view"; //$NON-NLS-1$ + + /** + * The constructor. + */ + public TerminalPlugin() { + fDefault = this; + } + /** + * Returns the shared instance. + */ + public static TerminalPlugin getDefault() { + return fDefault; + } + + public static boolean isLogInfoEnabled() { + return isOptionEnabled(Logger.TRACE_DEBUG_LOG_INFO); + } + public static boolean isLogErrorEnabled() { + return isOptionEnabled(Logger.TRACE_DEBUG_LOG_ERROR); + } + public static boolean isLogEnabled() { + return isOptionEnabled(Logger.TRACE_DEBUG_LOG); + } + + public static boolean isOptionEnabled(String strOption) { + String strEnabled = Platform.getDebugOption(strOption); + if (strEnabled == null) + return false; + + return new Boolean(strEnabled).booleanValue(); + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalText.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalText.java new file mode 100644 index 00000000000..e32ed244347 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/control/TerminalText.java @@ -0,0 +1,2081 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.control; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.core.runtime.Preferences; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; +import org.eclipse.tm.terminal.internal.telnet.TelnetConnection; + +/** + * This class processes character data received from the remote host and + * displays it to the user using the Terminal view's StyledText widget. This + * class processes ANSI control characters, including NUL, backspace, carriage + * return, linefeed, and a subset of ANSI escape sequences sufficient to allow + * use of screen-oriented applications, such as vi, Emacs, and any GNU + * readline-enabled application (Bash, bc, ncftp, etc.). + *

+ * + * @author Fran Litterio + * @author Chris Thew + */ +public class TerminalText implements Runnable, ControlListener { + /** This is a character processing state: Initial state. */ + protected static final int ANSISTATE_INITIAL = 0; + + /** This is a character processing state: We've seen an escape character. */ + protected static final int ANSISTATE_ESCAPE = 1; + + /** + * This is a character processing state: We've seen a '[' after an escape + * character. Expecting a parameter character or a command character next. + */ + protected static final int ANSISTATE_EXPECTING_PARAMETER_OR_COMMAND = 2; + + /** + * This is a character processing state: We've seen a ']' after an escape + * character. We are now expecting an operating system command that + * reprograms an intelligent terminal. + */ + protected static final int ANSISTATE_EXPECTING_OS_COMMAND = 3; + + /** + * This field holds the current state of the Finite TerminalState Automaton (FSA) + * that recognizes ANSI escape sequences. + * + * @see #processNewText() + */ + protected int ansiState = ANSISTATE_INITIAL; + + /** + * This field holds a reference to the {@link TerminalControl} object that + * instantiates this class. + */ + protected ITerminalControlForText terminal; + + /** + * This field holds a reference to the StyledText widget that is used to + * display text to the user. + */ + protected StyledText text; + + /** + * This field holds the characters received from the remote host before they + * are displayed to the user. Method {@link #processNewText()} scans this + * text looking for ANSI control characters and escape sequences. + */ + protected StringBuffer newText; + + /** + * This field holds the index of the current character while the text stored + * in field {@link #newText} is being processed. + */ + protected int characterIndex = 0; + + /** + * This field holds the width of a character (in pixels) for the font used + * to display text. + */ + protected int characterPixelWidth = 0; + + /** + * This field holds the width of the terminal screen in columns. + */ + protected int widthInColumns = 0; + + /** + * This field holds the height of the terminal screen in visible lines. The + * StyledText widget can contain more lines than are visible. + */ + protected int heightInLines = 0; + + /** + * 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. + *

+ * + * 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. + *

+ * + * When cursorColumn 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. + *

+ */ + protected int cursorColumn = 0; + + /** + * This field holds the caret offset when we last moved it or wrote text to + * the terminal. The reason we need to remember this value is because, + * unlike with a normal terminal emulator, the user can move the caret by + * clicking anywhere in the terminal view. In a normal terminal emulator, + * the cursor only moves as the result of character output (i.e., escape + * sequences or normal characters). We use the value stored in this field to + * restore the position of the caret immediately before processing each + * chunk of output from the remote endpoint. + */ + protected int caretOffset = 0; + + /** + * This field hold the saved absolute line number of the cursor when + * processing the "ESC 7" and "ESC 8" command sequences. + */ + protected int savedCursorLine = 0; + + /** + * This field hold the saved column number of the cursor when processing the + * "ESC 7" and "ESC 8" command sequences. + */ + protected int savedCursorColumn = 0; + + /** + * This field holds an array of StringBuffer objects, each of which is one + * parameter from the current ANSI escape sequence. For example, when + * parsing the escape sequence "\e[20;10H", this array holds the strings + * "20" and "10". + */ + protected StringBuffer[] ansiParameters = new StringBuffer[16]; + + /** + * This field holds the OS-specific command found in an escape sequence of + * the form "\e]...\u0007". + */ + protected StringBuffer ansiOsCommand = new StringBuffer(128); + + /** + * This field holds the index of the next unused element of the array stored + * in field {@link #ansiParameters}. + */ + protected int nextAnsiParameter = 0; + + /** + * This field holds the Color object representing the current foreground + * color as set by the ANSI escape sequence "\e[m". + */ + protected Color currentForegroundColor; + + /** + * This field holds the Color object representing the current background + * color as set by the ANSI escape sequence "\e[m". + */ + protected Color currentBackgroundColor; + + /** + * This field holds an integer representing the current font style as set by + * the ANSI escape sequence "\e[m". + */ + protected int currentFontStyle = SWT.NORMAL; + + /** + * This field is true if we are currently outputing text in reverse video + * mode, false otherwise. + */ + protected boolean reverseVideo = false; + + /** + * This field holds the time (in milliseconds) of the previous call to + * method {@link #SetNewText()}. + */ + static long LastNewOutputTime = 0; + + /** + * Color object representing the color black. The Color class requires us to + * call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color BLACK = new Color(Display.getCurrent(), 0, 0, 0); + + /** + * Color object representing the color red. The Color class requires us to + * call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color RED = new Color(Display.getCurrent(), 255, 0, 0); + + /** + * Color object representing the color green. The Color class requires us to + * call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color GREEN = new Color(Display.getCurrent(), 0, 255, 0); + + /** + * Color object representing the color yellow. The Color class requires us + * to call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color YELLOW = new Color(Display.getCurrent(), 255, 255, 0); + + /** + * Color object representing the color blue. The Color class requires us to + * call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color BLUE = new Color(Display.getCurrent(), 0, 0, 255); + + /** + * Color object representing the color magenta. The Color class requires us + * to call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color MAGENTA = new Color(Display.getCurrent(), 255, 0, 255); + + /** + * Color object representing the color cyan. The Color class requires us to + * call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color CYAN = new Color(Display.getCurrent(), 0, 255, 255); + + /** + * Color object representing the color white. The Color class requires us to + * call dispose() on this object when we no longer need it. We do that in + * method {@link #dispose()}. + */ + protected final Color WHITE = new Color(Display.getCurrent(), 255, 255, 255); + + protected boolean fLimitOutput; + protected int fBufferLineLimit; + /** + * The constructor. + */ + public TerminalText(ITerminalControlForText terminal) { + super(); + + Logger.log("entered"); //$NON-NLS-1$ + + this.terminal = terminal; + + for (int i = 0; i < ansiParameters.length; ++i) { + ansiParameters[i] = new StringBuffer(); + } + } + + /** + * @param ctlText Sets the styled text. + * + *

Note:This method can only be called once. + */ + public void setStyledText(StyledText ctlText) { + if(text!=null) + throw new java.lang.IllegalStateException("Text can be set only once"); //$NON-NLS-1$ + text=ctlText; + + // Register this class instance as a ControlListener so we can learn + // when the StyledText widget is resized. + + text.addControlListener(this); + + currentForegroundColor = text.getForeground(); + currentBackgroundColor = text.getBackground(); + currentFontStyle = SWT.NORMAL; + reverseVideo = false; + } + + + /** + * This method performs clean up when this TerminalText object is no longer + * needed. After calling this method, no other method on this object should + * be called. + */ + public void dispose() { + Logger.log("entered"); //$NON-NLS-1$ + + // Call dispose() on the Color objects we created. + + BLACK.dispose(); + RED.dispose(); + GREEN.dispose(); + YELLOW.dispose(); + BLUE.dispose(); + MAGENTA.dispose(); + CYAN.dispose(); + WHITE.dispose(); + } + + /** + * This method is required by interface ControlListener. It allows us to + * know when the StyledText widget is moved. + */ + public void controlMoved(ControlEvent event) { + Logger.log("entered"); //$NON-NLS-1$ + // Empty. + } + + /** + * This method is required by interface ControlListener. It allows us to + * know when the StyledText widget is resized. This method must be + * synchronized to prevent it from executing at the same time as run(), + * which displays new text. We can't have the fields that represent the + * dimensions of the terminal changing while we are rendering text. + */ + public synchronized void controlResized(ControlEvent event) { + Logger.log("entered"); //$NON-NLS-1$ + adjustTerminalDimensions(); + } + + /** + * This method sets field {@link #newText} to a new value. This method must + * not execute at the same time as methods {@link #run()} and {@link + * #clearTerminal()}. + *

+ * + * IMPORTANT: This method must be called in strict alternation with method + * {@link #run()}. + *

+ * + * @param newBuffer + * The new buffer containing characters received from the remote + * host. + */ + public synchronized void setNewText(StringBuffer newBuffer) { + Logger.log("new text: '" + newBuffer + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + newText = newBuffer; + + // When continuous output is being processed by the Terminal view code, it + // consumes nearly 100% of the CPU. This fixes that. If this method is called + // too frequently, we explicitly sleep for a short time so that the thread + // executing this function (which is the thread reading from the socket or + // serial port) doesn't consume 100% of the CPU. Without this code, the + // Workbench GUI is practically hung when there is continuous output in the + // Terminal view. + + long CurrentTime = System.currentTimeMillis(); + + if (CurrentTime - LastNewOutputTime < 250 && newBuffer.length() > 10) { + try { + Thread.sleep(50); + } catch (InterruptedException ex) { + // Ignore. + } + } + + LastNewOutputTime = CurrentTime; + } + + /** + * This method erases all text from the Terminal view. This method is called + * when the user chooses "Clear all" from the Terminal view context menu, so + * we need to serialize this method with methods {@link #run()} and {@link + * #setNewText(StringBuffer)}. + */ + public synchronized void clearTerminal() { + Logger.log("entered"); //$NON-NLS-1$ + text.setText(""); //$NON-NLS-1$ + cursorColumn = 0; + } + + /** + * This method is called when the user changes the Terminal view's font. We + * attempt to recompute the pixel width of the new font's characters and fix + * the terminal's dimensions. This method must be synchronized to prevent it + * from executing at the same time as run(), which displays new text. We + * can't have the fields that represent the dimensions of the terminal + * changing while we are rendering text. + */ + public synchronized void fontChanged() { + Logger.log("entered"); //$NON-NLS-1$ + + characterPixelWidth = 0; + + if (text != null) + adjustTerminalDimensions(); + } + + /** + * This method executes in the Display thread to process data received from + * the remote host by classes {@link TelnetConnection} and {@link + * SerialPortHandler}. This method must not execute at the same time + * as methods {@link #setNewText(StringBuffer)} and {@link #clearTerminal()}. + *

+ * + * IMPORTANT: This method must be called in strict alternation with method + * {@link #setNewText(StringBuffer)}. + *

+ */ + public synchronized void run() { + Logger.log("entered"); //$NON-NLS-1$ + + try { + // This method can be called just after the user closes the view, so we + // make sure not to cause a widget-disposed exception. + + if (text != null && text.isDisposed()) + return; + + // If the status bar is showing "OPENED", change it to "CONNECTED". + + if (terminal.getState()==TerminalState.OPENED) { + // TODO Why???? + terminal.setState(TerminalState.CONNECTED); + } + + // Find the width and height of the terminal, and resize it to display an + // integral number of lines and columns. + + adjustTerminalDimensions(); + + // Restore the caret offset, process and display the new text, then save + // the caret offset. See the documentation for field caretOffset for + // details. + + // ISSUE: Is this causing the scroll-to-bottom-on-output behavior? + + text.setCaretOffset(caretOffset); + + processNewText(); + + caretOffset = text.getCaretOffset(); + } catch (Exception ex) { + Logger.logException(ex); + } + } + + /** + * This method scans the newly received text, processing ANSI control + * characters and escape sequences and displaying normal text. + */ + protected void processNewText() { + Logger.log("entered"); //$NON-NLS-1$ + + // Stop the StyledText widget from redrawing while we manipulate its contents. + // This helps display performance. + + text.setRedraw(false); + + // Scan the newly received text. + + characterIndex = 0; + + while (characterIndex < newText.length()) { + char character = newText.charAt(characterIndex); + + switch (ansiState) { + case ANSISTATE_INITIAL: + switch (character) { + case '\u0000': + break; // NUL character. Ignore it. + + case '\u0007': + processBEL(); // BEL (Control-G) + break; + + case '\b': + processBackspace(); // Backspace + break; + + case '\t': + processTab(); // Tab. + break; + + case '\n': + processNewline(); // Newline (Control-J) + break; + + case '\r': + processCarriageReturn(); // Carriage Return (Control-M) + break; + + case '\u001b': + ansiState = ANSISTATE_ESCAPE; // Escape. + break; + + default: + processNonControlCharacters(); + break; + } + break; + + case ANSISTATE_ESCAPE: + // We've seen an escape character. Here, we process the character + // immediately following the escape. + + switch (character) { + case '[': + ansiState = ANSISTATE_EXPECTING_PARAMETER_OR_COMMAND; + nextAnsiParameter = 0; + + // Erase the parameter strings in preparation for optional + // parameter characters. + + for (int i = 0; i < ansiParameters.length; ++i) { + ansiParameters[i].delete(0, ansiParameters[i].length()); + } + break; + + case ']': + ansiState = ANSISTATE_EXPECTING_OS_COMMAND; + ansiOsCommand.delete(0, ansiOsCommand.length()); + break; + + case '7': + // Save cursor position and character attributes + + ansiState = ANSISTATE_INITIAL; + savedCursorLine = absoluteCursorLine(); + savedCursorColumn = cursorColumn; + break; + + case '8': + // Restore cursor and attributes to previously saved + // position + + ansiState = ANSISTATE_INITIAL; + moveCursor(savedCursorLine, savedCursorColumn); + break; + + default: + Logger + .log("Unsupported escape sequence: escape '" + character + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + ansiState = ANSISTATE_INITIAL; + break; + } + break; + + case ANSISTATE_EXPECTING_PARAMETER_OR_COMMAND: + // Parameters can appear after the '[' in an escape sequence, but they + // are optional. + + if (character == '@' || (character >= 'A' && character <= 'Z') + || (character >= 'a' && character <= 'z')) { + ansiState = ANSISTATE_INITIAL; + processAnsiCommandCharacter(character); + } else { + processAnsiParameterCharacter(character); + } + break; + + case ANSISTATE_EXPECTING_OS_COMMAND: + // A BEL (\u0007) character marks the end of the OSC sequence. + + if (character == '\u0007') { + ansiState = ANSISTATE_INITIAL; + processAnsiOsCommand(); + } else { + ansiOsCommand.append(character); + } + break; + + default: + // This should never happen! If it does happen, it means there is a + // bug in the FSA. For robustness, we return to the initial + // state. + + Logger.log("INVALID ANSI FSA STATE: " + ansiState); //$NON-NLS-1$ + ansiState = ANSISTATE_INITIAL; + break; + } + + ++characterIndex; + } + + // Allow the StyledText widget to redraw itself. + + text.setRedraw(true); + } + + /** + * This method is called when we have parsed an OS Command escape sequence. + * The only one we support is "\e]0;...\u0007", which sets the terminal + * title. + */ + protected void processAnsiOsCommand() { + if (ansiOsCommand.charAt(0) != '0' || ansiOsCommand.charAt(1) != ';') { + Logger + .log("Ignoring unsupported ANSI OSC sequence: '" + ansiOsCommand + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + return; + } + terminal.setTerminalTitle(ansiOsCommand.substring(2)); + } + + /** + * This method dispatches control to various processing methods based on the + * command character found in the most recently received ANSI escape + * sequence. This method only handles command characters that follow the + * ANSI standard Control Sequence Introducer (CSI), which is "\e[...", where + * "..." is an optional ';'-separated sequence of numeric parameters. + *

+ */ + protected void processAnsiCommandCharacter(char ansiCommandCharacter) { + // If the width or height of the terminal is ridiculously small (one line or + // column or less), don't even try to process the escape sequence. This avoids + // throwing an exception (SPR 107450). The display will be messed up, but what + // did you user expect by making the terminal so small? + + if (heightInLines <= 1 || widthInColumns <= 1) + return; + + switch (ansiCommandCharacter) { + case '@': + // Insert character(s). + processAnsiCommand_atsign(); + break; + + case 'A': + // Move cursor up N lines (default 1). + processAnsiCommand_A(); + break; + + case 'B': + // Move cursor down N lines (default 1). + processAnsiCommand_B(); + break; + + case 'C': + // Move cursor forward N columns (default 1). + processAnsiCommand_C(); + break; + + case 'D': + // Move cursor backward N columns (default 1). + processAnsiCommand_D(); + break; + + case 'E': + // Move cursor to first column of Nth next line (default 1). + processAnsiCommand_E(); + break; + + case 'F': + // Move cursor to first column of Nth previous line (default 1). + processAnsiCommand_F(); + break; + + case 'G': + // Move to column N of current line (default 1). + processAnsiCommand_G(); + break; + + case 'H': + // Set cursor Position. + processAnsiCommand_H(); + break; + + case 'J': + // Erase part or all of display. Cursor does not move. + processAnsiCommand_J(); + break; + + case 'K': + // Erase in line (cursor does not move). + processAnsiCommand_K(); + break; + + case 'L': + // Insert line(s) (current line moves down). + processAnsiCommand_L(); + break; + + case 'M': + // Delete line(s). + processAnsiCommand_M(); + break; + + case 'm': + // Set Graphics Rendition (SGR). + processAnsiCommand_m(); + break; + + case 'n': + // Device Status Report (DSR). + processAnsiCommand_n(); + break; + + case 'P': + // Delete character(s). + processAnsiCommand_P(); + break; + + case 'S': + // Scroll up. + // Emacs, vi, and GNU readline don't seem to use this command, so we ignore + // it for now. + break; + + case 'T': + // Scroll down. + // Emacs, vi, and GNU readline don't seem to use this command, so we ignore + // it for now. + break; + + case 'X': + // Erase character. + // Emacs, vi, and GNU readline don't seem to use this command, so we ignore + // it for now. + break; + + case 'Z': + // Cursor back tab. + // Emacs, vi, and GNU readline don't seem to use this command, so we ignore + // it for now. + break; + + default: + Logger.log("Ignoring unsupported ANSI command character: '" + //$NON-NLS-1$ + ansiCommandCharacter + "'"); //$NON-NLS-1$ + break; + } + } + + /** + * 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 hte line. + */ + protected void processAnsiCommand_atsign() { + int charactersToInsert = getAnsiParameter(0); + int caretOffset = text.getCaretOffset(); + + text.replaceTextRange(caretOffset, 0, generateString(' ', + charactersToInsert)); + + // If the current line extends past the right edge of the screen, delete the + // characters beyond the rightmost visible column. + + int currentLineAbsolute = absoluteCursorLine(); + int currentLineStartOffset = text.getOffsetAtLine(currentLineAbsolute); + int currentLineEndOffset; + + if (currentLineAbsolute == text.getLineCount() - 1) { + // The cursor is on the bottommost line of text. + + currentLineEndOffset = text.getCharCount(); + } else { + // The cursor is not on the bottommost line of text. + + currentLineEndOffset = text + .getOffsetAtLine(currentLineAbsolute + 1) - 1; + } + + if (currentLineEndOffset - currentLineStartOffset > widthInColumns) { + int charactersToDelete = currentLineEndOffset + - currentLineStartOffset - widthInColumns; + + text.replaceTextRange(currentLineStartOffset + widthInColumns, + charactersToDelete, ""); //$NON-NLS-1$ + } + + // Is this necessary? + + text.setCaretOffset(caretOffset); + } + + /** + * This method moves the cursor up by the number of lines specified by the + * escape sequence parameter (default 1). + */ + protected void processAnsiCommand_A() { + moveCursorUp(getAnsiParameter(0)); + } + + /** + * This method moves the cursor down by the number of lines specified by the + * escape sequence parameter (default 1). + */ + protected void processAnsiCommand_B() { + moveCursorDown(getAnsiParameter(0)); + } + + /** + * This method moves the cursor forward by the number of columns specified + * by the escape sequence parameter (default 1). + */ + protected void processAnsiCommand_C() { + moveCursorForward(getAnsiParameter(0)); + } + + /** + * This method moves the cursor backward by the number of columns specified + * by the escape sequence parameter (default 1). + */ + protected void processAnsiCommand_D() { + moveCursorBackward(getAnsiParameter(0)); + } + + /** + * This method moves the cursor to the first column of the Nth next line, + * where N is specified by the ANSI parameter (default 1). + */ + protected void processAnsiCommand_E() { + int linesToMove = getAnsiParameter(0); + + moveCursor(relativeCursorLine() + linesToMove, 0); + } + + /** + * This method moves the cursor to the first column of the Nth previous + * line, where N is specified by the ANSI parameter (default 1). + */ + protected void processAnsiCommand_F() { + int linesToMove = getAnsiParameter(0); + + moveCursor(relativeCursorLine() - linesToMove, 0); + } + + /** + * This method moves the cursor within the current line to the column + * specified by the ANSI parameter (default is column 1). + */ + protected void processAnsiCommand_G() { + int targetColumn = 1; + + if (ansiParameters[0].length() > 0) + targetColumn = getAnsiParameter(0) - 1; + + moveCursor(relativeCursorLine(), targetColumn); + } + + /** + * This method sets the cursor to a position specified by the escape + * sequence parameters (default is the upper left corner of the screen). + */ + protected void processAnsiCommand_H() { + moveCursor(getAnsiParameter(0) - 1, getAnsiParameter(1) - 1); + } + + /** + * This method deletes some (or all) of the text on the screen without + * moving the cursor. + */ + protected void processAnsiCommand_J() { + int ansiParameter; + + if (ansiParameters[0].length() == 0) + ansiParameter = 0; + else + ansiParameter = getAnsiParameter(0); + + switch (ansiParameter) { + case 0: + // Erase from current position to end of screen (inclusive). + + int caretOffset = text.getCaretOffset(); + + text.replaceTextRange(caretOffset, text.getCharCount() + - caretOffset, generateString('\n', heightInLines + - relativeCursorLine() - 1)); + + // The above call moves the caret to the end of the text, so restore its + // position. + + text.setCaretOffset(caretOffset); + break; + + case 1: + // Erase from beginning to current position (inclusive). + + int currentRelativeLineNumber = relativeCursorLine(); + int topmostScreenLineStartOffset = text + .getOffsetAtLine(absoluteLine(0)); + + text.replaceTextRange(topmostScreenLineStartOffset, text + .getCaretOffset() + - topmostScreenLineStartOffset, generateString('\n', + currentRelativeLineNumber) + + generateString(' ', cursorColumn)); + + text.setCaretOffset(topmostScreenLineStartOffset + + currentRelativeLineNumber + cursorColumn); + break; + + case 2: + // Erase entire display. + + int currentLineNumber = relativeCursorLine(); + topmostScreenLineStartOffset = text + .getOffsetAtLine(absoluteLine(0)); + + text.replaceTextRange(topmostScreenLineStartOffset, text + .getCharCount() + - topmostScreenLineStartOffset, generateString('\n', + heightInLines - 1)); + + moveCursor(currentLineNumber, cursorColumn); + break; + + default: + Logger.log("Unexpected J-command parameter: " + ansiParameter); //$NON-NLS-1$ + break; + } + } + + /** + * This method deletes some (or all) of the text in the current line without + * moving the cursor. + */ + protected void processAnsiCommand_K() { + int ansiParameter = getAnsiParameter(0); + int originalCaretOffset = text.getCaretOffset(); + + switch (ansiParameter) { + case 0: + // Erase from beginning to current position (inclusive). + + int currentLineStartOffset = text + .getOffsetAtLine(absoluteCursorLine()); + + text.replaceTextRange(currentLineStartOffset, cursorColumn, + generateString(' ', cursorColumn)); + break; + + case 1: + // Erase from current position to end (inclusive). + + int caretOffset = text.getCaretOffset(); + + if (absoluteCursorLine() == text.getLineCount() - 1) { + text.replaceTextRange(caretOffset, text.getCharCount() + - caretOffset, ""); //$NON-NLS-1$ + } else { + int nextLineStartOffset = text + .getOffsetAtLine(absoluteCursorLine() + 1); + + text.replaceTextRange(caretOffset, nextLineStartOffset + - caretOffset - 1, ""); //$NON-NLS-1$ + } + break; + + case 2: + // Erase entire line. + + currentLineStartOffset = text.getOffsetAtLine(absoluteCursorLine()); + + if (absoluteCursorLine() == text.getLineCount() - 1) { + // The cursor is on the bottommost line of text. Replace its contents + // with enough spaces to leave the cursor in the current column. + + text.replaceTextRange(currentLineStartOffset, text + .getCharCount() + - currentLineStartOffset, generateString(' ', + cursorColumn)); + } else { + // The cursor is not on the bottommost line of text. Replace the + // current line's contents with enough spaces to leave the cursor in + // the current column. + + int nextLineStartOffset = text + .getOffsetAtLine(absoluteCursorLine() + 1); + + text.replaceTextRange(currentLineStartOffset, + nextLineStartOffset - currentLineStartOffset - 1, + generateString(' ', cursorColumn)); + } + break; + + default: + Logger.log("Unexpected K-command parameter: " + ansiParameter); //$NON-NLS-1$ + break; + } + + // There is some undocumented strangeness with method + // StyledText.replaceTextRange() that requires us to manually reposition the + // caret after calling that method. If we don't do this, the caret sometimes + // moves to the very end of the text when deleting text within a line. + + text.setCaretOffset(originalCaretOffset); + } + + /** + * Insert one or more blank lines. The current line of text moves down. Text + * that falls off the bottom of the screen is deleted. + */ + protected void processAnsiCommand_L() { + int linesToInsert = getAnsiParameter(0); + + int currentLineStartOffset = text.getOffsetAtLine(absoluteCursorLine()); + + // Compute how many of the bottommost lines of text to delete. This is + // necessary if those lines are being pushed off the bottom of the screen by + // the insertion of the blank lines. + + int totalLines = text.getLineCount(); + int linesToDelete = -1; + + if (heightInLines <= totalLines) { + // There are more lines of text than are displayed, so delete as many lines + // at the end as we insert in the middle. + + linesToDelete = linesToInsert; + } else { + // There are fewer lines of text than the size of the terminal window, so + // compute how many lines will be pushed off the end of the screen by the + // insertion. NOTE: It is possible that we may not have to delete any + // lines at all, which will leave linesToDelete set to -1. + + if (totalLines + linesToInsert > heightInLines) { + linesToDelete = (totalLines + linesToInsert) - heightInLines; + } + } + + if (linesToDelete != -1) { + // Delete the bottomost linesToInsert lines plus the newline on the line + // immediately above the first line to be deleted. + + int firstLineToDeleteStartOffset = text.getOffsetAtLine(totalLines + - linesToDelete); + + text.replaceTextRange(firstLineToDeleteStartOffset - 1, text + .getCharCount() + - firstLineToDeleteStartOffset + 1, ""); //$NON-NLS-1$ + } + + // Insert the new blank lines, leaving the cursor on the topmost of the new + // blank lines. + + int totalCharacters = text.getCharCount(); + + if (currentLineStartOffset > totalCharacters) { + // We are inserting the blank lines at the very end of the text, so + // currentLineStartOffset is now out of range. It will be be in range + // again after these newlines are appended. + + text.replaceTextRange(totalCharacters, 0, generateString('\n', + linesToInsert)); + } else { + // We are inserting the blank lines in the middle of the text, so + // currentLineStartOffset is not out of range. + + text.replaceTextRange(currentLineStartOffset, 0, generateString( + '\n', linesToInsert)); + } + + text.setCaretOffset(currentLineStartOffset); + } + + /** + * Delete one or more lines of text. Any lines below the deleted lines move + * up, which we implmement by appending newlines to the end of the text. + */ + protected void processAnsiCommand_M() { + int totalLines = text.getLineCount(); + int linesToDelete = getAnsiParameter(0); + int currentLineAbsolute = absoluteCursorLine(); + int currentLineStartOffset = text.getOffsetAtLine(currentLineAbsolute); + + // Compute the offset of the character after the lines to be deleted. This + // might be the end of the text. + + if (linesToDelete >= totalLines - currentLineAbsolute) { + // We are deleting all the lines to the bottom of the text. Replace them + // with blank lines. + + text.replaceTextRange(currentLineStartOffset, text.getCharCount() + - currentLineStartOffset, generateString('\n', totalLines + - currentLineAbsolute - 1)); + } else { + // Delete the next linesToDelete lines. + + int firstUndeletedLineStartOffset = text + .getOffsetAtLine(currentLineAbsolute + linesToDelete); + + text.replaceTextRange(currentLineStartOffset, + firstUndeletedLineStartOffset - currentLineStartOffset, ""); //$NON-NLS-1$ + + // Add an equal number of blank lines to the end of the text. + + text.replaceTextRange(text.getCharCount(), 0, generateString('\n', + linesToDelete)); + } + + text.setCaretOffset(currentLineStartOffset); + } + + /** + * This method sets a new graphics rendition mode, such as + * foreground/background color, bold/normal text, and reverse video. + */ + protected void processAnsiCommand_m() { + if (ansiParameters[0].length() == 0) { + // This a special case: when no ANSI parameter is specified, act like a + // single parameter equal to 0 was specified. + + ansiParameters[0].append('0'); + } + + // There are a non-zero number of ANSI parameters. Process each one in + // order. + + int totalParameters = ansiParameters.length; + int parameterIndex = 0; + + while (parameterIndex < totalParameters + && ansiParameters[parameterIndex].length() > 0) { + int ansiParameter = getAnsiParameter(parameterIndex); + + switch (ansiParameter) { + case 0: + // Reset all graphics modes. + currentForegroundColor = text.getForeground(); + currentBackgroundColor = text.getBackground(); + currentFontStyle = SWT.NORMAL; + reverseVideo = false; + break; + + case 1: + currentFontStyle = SWT.BOLD; // Turn on bold. + break; + + case 7: + reverseVideo = true; // Reverse video. + break; + + case 10: // Set primary font. Ignored. + break; + + case 22: + currentFontStyle = SWT.NORMAL; // Cancel bold or dim attributes + // only. + break; + + case 27: + reverseVideo = false; // Cancel reverse video attribute only. + break; + + case 30: + currentForegroundColor = BLACK; // Foreground is black. + break; + + case 31: + currentForegroundColor = RED; // Foreground is red. + break; + + case 32: + currentForegroundColor = GREEN; // Foreground is green. + break; + + case 33: + currentForegroundColor = YELLOW; // Foreground is yellow. + break; + + case 34: + currentForegroundColor = BLUE; // Foreground is blue. + break; + + case 35: + currentForegroundColor = MAGENTA; // Foreground is magenta. + break; + + case 36: + currentForegroundColor = CYAN; // Foreground is cyan. + break; + + case 37: + currentForegroundColor = text.getForeground(); // Foreground is + // white. + break; + + case 40: + currentBackgroundColor = text.getBackground(); // Background is + // black. + break; + + case 41: + currentBackgroundColor = RED; // Background is red. + break; + + case 42: + currentBackgroundColor = GREEN; // Background is green. + break; + + case 43: + currentBackgroundColor = YELLOW; // Background is yellow. + break; + + case 44: + currentBackgroundColor = BLUE; // Background is blue. + break; + + case 45: + currentBackgroundColor = MAGENTA; // Background is magenta. + break; + + case 46: + currentBackgroundColor = CYAN; // Background is cyan. + break; + + case 47: + currentBackgroundColor = WHITE; // Background is white. + break; + + default: + Logger + .log("Unsupported graphics rendition parameter: " + ansiParameter); //$NON-NLS-1$ + break; + } + + ++parameterIndex; + } + } + + /** + * This method responds to an ANSI Device Status Report (DSR) command from + * the remote endpoint requesting the cursor position. Requests for other + * kinds of status are ignored. + */ + protected void processAnsiCommand_n() { + // Do nothing if the numeric parameter was not 6 (which means report cursor + // position). + + if (getAnsiParameter(0) != 6) + return; + + // Send the ANSI cursor position (which is 1-based) to the remote endpoint. + + String positionReport = "\u001b[" + (relativeCursorLine() + 1) + ";" + //$NON-NLS-1$ //$NON-NLS-2$ + (cursorColumn + 1) + "R"; //$NON-NLS-1$ + + OutputStreamWriter streamWriter = new OutputStreamWriter(terminal + .getOutputStream(), Charset.forName("ISO-8859-1")); //$NON-NLS-1$ + + try { + streamWriter.write(positionReport, 0, positionReport.length()); + streamWriter.flush(); + } catch (IOException ex) { + Logger.log("Caught IOException!"); //$NON-NLS-1$ + } + } + + /** + * Deletes one or more characters starting at the current cursor position. + * Characters on the same line and to the right of the deleted characters + * move left. If there are no characters on the current line at or to the + * right of the cursor column, no text is deleted. + */ + protected void processAnsiCommand_P() { + int currentLineEndOffset; + int currentLineAbsolute = absoluteCursorLine(); + + if (currentLineAbsolute == text.getLineCount() - 1) { + // The cursor is on the bottommost line of text. + + currentLineEndOffset = text.getCharCount(); + } else { + // The cursor is not on the bottommost line of text. + + currentLineEndOffset = text + .getOffsetAtLine(currentLineAbsolute + 1) - 1; + } + + int caretOffset = text.getCaretOffset(); + int remainingCharactersOnLine = currentLineEndOffset - caretOffset; + + if (remainingCharactersOnLine > 0) { + // There are characters that can be deleted. + + int charactersToDelete = getAnsiParameter(0); + + if (charactersToDelete > remainingCharactersOnLine) + charactersToDelete = remainingCharactersOnLine; + + text.replaceTextRange(caretOffset, charactersToDelete, ""); //$NON-NLS-1$ + text.setCaretOffset(caretOffset); + } + } + + /** + * This method returns one of the numeric ANSI parameters received in the + * most recent escape sequence. + * + * @return The parameterIndexth numeric ANSI parameter or -1 if the + * index is out of range. + */ + protected int getAnsiParameter(int parameterIndex) { + if (parameterIndex < 0 || parameterIndex >= ansiParameters.length) { + // This should never happen. + return -1; + } + + String parameter = ansiParameters[parameterIndex].toString(); + + if (parameter.length() == 0) + return 1; + + int parameterValue = 1; + + // Don't trust the remote endpoint to send well formed numeric + // parameters. + + try { + parameterValue = Integer.parseInt(parameter); + } catch (NumberFormatException ex) { + parameterValue = 1; + } + + return parameterValue; + } + + /** + * This method processes a single parameter character in an ANSI escape + * sequence. Paramters are the (optional) characters between the leading + * "\e[" and the command character in an escape sequence (e.g., in the + * escape sequence "\e[20;10H", the paramter characters are "20;10"). + * Parameters are integers separated by one or more ';'s. + */ + protected void processAnsiParameterCharacter(char ch) { + if (ch == ';') { + ++nextAnsiParameter; + } else { + if (nextAnsiParameter < ansiParameters.length) + ansiParameters[nextAnsiParameter].append(ch); + } + } + + /** + * This method processes a contiguous sequence of non-control characters. + * This is a performance optimization, so that we don't have to insert or + * append each non-control character individually to the StyledText widget. + * A non-control character is any character that passes the condition in the + * below while loop. + */ + protected void processNonControlCharacters() { + int firstNonControlCharacterIndex = characterIndex; + int newTextLength = newText.length(); + char character = newText.charAt(characterIndex); + + // Identify a contiguous sequence of non-control characters, starting at + // firstNonControlCharacterIndex in newText. + + while (character != '\u0000' && character != '\b' && character != '\t' + && character != '\u0007' && character != '\n' + && character != '\r' && character != '\u001b') { + ++characterIndex; + + if (characterIndex >= newTextLength) + break; + + character = newText.charAt(characterIndex); + } + + // Move characterIndex back by one character because it gets incremented at the + // bottom of the loop in processNewText(). + + --characterIndex; + + int preDisplayCaretOffset = text.getCaretOffset(); + + // Now insert the sequence of non-control characters in the StyledText widget + // at the location of the cursor. + + displayNewText(firstNonControlCharacterIndex, characterIndex); + + // If any one of the current font style, foreground color or background color + // differs from the defaults, apply the current style to the newly displayed + // text. Since this method is only called for a contiguous sequence of + // non-control characters, the current style applies to the entire + // sequence of characters. + + if (!currentForegroundColor.equals(text.getForeground()) + || !currentBackgroundColor.equals(text.getBackground()) + || currentFontStyle != SWT.NORMAL || reverseVideo == true) { + StyleRange style = new StyleRange(preDisplayCaretOffset, text + .getCaretOffset() + - preDisplayCaretOffset, + reverseVideo ? currentBackgroundColor + : currentForegroundColor, + reverseVideo ? currentForegroundColor + : currentBackgroundColor, currentFontStyle); + + text.setStyleRange(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. + *

+ * + * 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). + *

+ * + * @param first + * The index (within newText) of the first character to display. + * @param last + * The index (within newText) of the last character to display. + */ + protected void displayNewText(int first, int last) { + if (text.getCaretOffset() == text.getCharCount()) { + // The cursor is at the very end of the terminal's text, so we append the + // new text to the StyledText widget. + + displayNewTextByAppending(first, last); + } else { + // The cursor is not at the end of the screen's text, so we have to + // overwrite existing text. + + displayNewTextByOverwriting(first, last); + } + } + + /** + * This method displays new text by appending it to the end of the existing + * text, wrapping text that extends past the right edge of the screen. + *

+ * + * 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). + *

+ * + * @param first + * The index (within newText) of the first character to display. + * @param last + * The index (within newText) of the last character to display. + */ + protected void displayNewTextByAppending(int first, int last) { + int numCharsToOutput = last - first + 1; + int availableSpaceOnLine = widthInColumns - cursorColumn; + + if (numCharsToOutput >= availableSpaceOnLine) { + // We need to wrap the text, because it's longer than the available + // space on the current line. First, appends as many characters as + // will fit in the space remaining on the current line. + // + // NOTE: We don't line wrap the text in this method the same way we line + // wrap the text in method displayNewTextByOverwriting(), but this is by far + // the most common case, and it has to run the fastest. + + text.append(newText.substring(first, first + availableSpaceOnLine)); + first += availableSpaceOnLine; + + processCarriageReturn(); + processNewline(); + + while (first <= last) { + availableSpaceOnLine = widthInColumns; + + if (availableSpaceOnLine > last - first + 1) { + text.append(newText.substring(first, last + 1)); + cursorColumn = last - first + 1; + break; + } else { + text.append(newText.substring(first, first + + availableSpaceOnLine)); + first += availableSpaceOnLine; + + processCarriageReturn(); + processNewline(); + } + } + } else { + // We don't need to wrap the text. + + text.append(newText.substring(first, last + 1)); + cursorColumn += last - first + 1; + } + } + + /** + * This method displays new text by overwriting existing text, wrapping text + * that extends past the right edge of the screen. + *

+ * + * 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). + *

+ * + * @param first + * The index (within newText) of the first character to display. + * @param last + * The index (within newText) of the last character to display. + */ + protected void displayNewTextByOverwriting(int first, int last) { + // First, break new text into segments, based on where it needs to line wrap, + // so that each segment contains text that will appear on a separate + // line. + + List textSegments = new ArrayList(100); + + int availableSpaceOnLine = widthInColumns - cursorColumn; + + while (first <= last) { + String segment; + + if (last - first + 1 > availableSpaceOnLine) + segment = newText + .substring(first, first + availableSpaceOnLine); + else + segment = newText.substring(first, last + 1); + + textSegments.add(segment); + + first += availableSpaceOnLine; + availableSpaceOnLine = widthInColumns; + } + + // Next, for each segment, if the cursor is at the end of the text, append the + // segment along with a newline character. If the cursor is not at the end of + // the text, replace the next N characters starting at the cursor position with + // the segment, where N is the minimum of the length of the segment or the + // length of the rest of the current line. + + Iterator iter = textSegments.iterator(); + + while (iter.hasNext()) { + String segment = (String) iter.next(); + int caretOffset = text.getCaretOffset(); + + if (caretOffset == text.getCharCount()) { + // The cursor is at the end of the text, so just append the current + // segement along with a newline. + + text.append(segment); + + // If there is another segment to display, move the cursor to a new + // line. + + if (iter.hasNext()) { + processCarriageReturn(); + processNewline(); + } + } else { + // The cursor is not at the end of the text, so replace some or all of + // the text following the cursor on the current line with the current + // segment. + + int numCharactersAfterCursorOnLine; + + if (absoluteCursorLine() == text.getLineCount() - 1) { + // The cursor is on the last line of text. + numCharactersAfterCursorOnLine = text.getCharCount() + - caretOffset; + } else { + // The cursor is not on the last line of text. + numCharactersAfterCursorOnLine = text + .getOffsetAtLine(absoluteCursorLine() + 1) + - caretOffset - 1; + } + + int segmentLength = segment.length(); + int numCharactersToReplace; + + if (segmentLength < numCharactersAfterCursorOnLine) + numCharactersToReplace = segmentLength; + else + numCharactersToReplace = numCharactersAfterCursorOnLine; + + text.replaceTextRange(caretOffset, numCharactersToReplace, + segment); + text.setCaretOffset(caretOffset + segmentLength); + cursorColumn += segmentLength; + + // If there is another segment, move the cursor to the start of + // the + // next line. + + if (iter.hasNext()) { + cursorColumn = 0; + text.setCaretOffset(caretOffset + segmentLength + 1); + } else { + // We just inserted the last segment. If the current line is full, + // wrap the cursor onto a new line. + + if (cursorColumn == widthInColumns) { + processCarriageReturn(); + processNewline(); + } + } + } + } + } + + /** + * Process a BEL (Control-G) character. + */ + protected void processBEL() { + // ISSUE: Is there a better way to make a sound? This is not guaranteed to + // work on all platforms. + // TODO + java.awt.Toolkit.getDefaultToolkit().beep(); + } + + /** + * Process a backspace (Control-H) character. + */ + protected void processBackspace() { + moveCursorBackward(1); + } + + /** + * Process a tab (Control-I) character. We don't insert a tab character into + * the StyledText widget. Instead, we move the cursor forward to the next + * tab stop, without altering any of the text. Tab stops are every 8 + * columns. The cursor will never move past the rightmost column. + */ + protected void processTab() { + moveCursorForward(8 - (cursorColumn % 8)); + } + + /** + * 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. + *

+ * + * 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". + *

+ */ + protected void processNewline() { + int totalLines = text.getLineCount(); + int currentLineAbsolute = absoluteCursorLine(); + + if (currentLineAbsolute < totalLines - 1) { + // The cursor is not on the bottommost line of text, so we move the cursor + // to the same column on the next line. + + // TODO: If we can verify that the next character is a carriage return, we + // can optimize out the insertion of spaces that moveCursorDown() + // will do. + + moveCursorDown(1); + } else if (currentLineAbsolute == totalLines - 1) { + // The cursor is on the bottommost line of text, so we append a newline + // character to the end of the terminal's text (creating a new line on the + // screen) and insert cursorColumn spaces. + + text.append("\n"); //$NON-NLS-1$ + text.append(generateString(' ', cursorColumn)); + text.setCaretOffset(text.getCharCount()); + + // We may have scrolled a line off the top of the screen, so check + // if we + // need to delete some of the the oldest lines in the scroll buffer. + + deleteTopmostLines(); + } else { + // This should _never_ happen. If it does happen, it is a bug in this + // algorithm. + + Logger.log("SHOULD NOT BE REACHED!"); //$NON-NLS-1$ + } + } + + /** + * Process a Carriage Return (Control-M). + */ + protected void processCarriageReturn() { + // Move the cursor to the beginning of the current line. + + text.setCaretOffset(text.getOffsetAtLine(text.getLineAtOffset(text + .getCaretOffset()))); + cursorColumn = 0; + } + + /** + * This method computes the width of the terminal in columns and its height + * in lines, then adjusts the width and height of the view's StyledText + * widget so that it displays an integral number of lines and columns of + * text. The adjustment is always to shrink the widget vertically or + * horizontally, because if the control were to grow, it would be clipped by + * the edges of the view window (i.e., the view window does not become + * larger to accommodate its contents becoming larger). + *

+ * + * This method must be called immediately before each time text is written + * to the terminal so that we can properly line wrap text. Because it is + * called so frequently, it must be fast when there is no resizing to be + * done. + *

+ */ + protected void adjustTerminalDimensions() { + // Compute how many pixels we need to shrink the StyledText control vertically + // to make it display an integral number of lines of text. + + int linePixelHeight = text.getLineHeight(); + Point textWindowDimensions = text.getSize(); + int verticalPixelsToShrink = textWindowDimensions.y % linePixelHeight; + + // Compute the current height of the terminal in lines. + + heightInLines = textWindowDimensions.y / linePixelHeight; + + // Compute how many pixels we need to shrink the StyledText control to make + // it display an integral number of columns of text. We can only do this if we + // know the pixel width of a character in the font used by the StyledText + // widget. + + int horizontalPixelsToShrink = 0; + + if (characterPixelWidth == 0) + computeCharacterPixelWidth(); + + if (characterPixelWidth != 0) { + horizontalPixelsToShrink = textWindowDimensions.x + % characterPixelWidth; + + // The width of the StyledText widget that text.getSize() returns includes + // the space occupied by the vertical scrollbar, so we have to fudge this + // calculation (by subtracting 3 columns) to account for the presence of + // the scrollbar. Ugh. + + widthInColumns = textWindowDimensions.x / characterPixelWidth - 3; + } + + // If necessary, resize the text widget. + + if (verticalPixelsToShrink > 0 || horizontalPixelsToShrink > 0) { + // Remove this class instance from being a ControlListener on the + // StyledText widget, because we are about to resize and move the widget, + // and we don't want this method to be recursively invoked. + + text.removeControlListener(this); + + // Shrink the StyledText control so that it displays an integral number + // of lines of text and an integral number of columns of text. + + textWindowDimensions.y -= verticalPixelsToShrink; + textWindowDimensions.x -= horizontalPixelsToShrink; + text.setSize(textWindowDimensions); + + // Move the StyledText control down by the same number of pixels that + // we just shrank it vertically and right by the same number of pixels that + // we just shrank it horizontally. This makes the padding appear to the + // left and top of the widget, which is more visually appealing. This is + // only necessary because there is no way to programmatically shrink the + // view itself. + + Point textLocation = text.getLocation(); + textLocation.y += verticalPixelsToShrink; + textLocation.x += horizontalPixelsToShrink; + text.setLocation(textLocation); + + // Restore this class instance as the ControlListener on the StyledText + // widget so we know when the user resizes the Terminal view. + + text.addControlListener(this); + + // Make sure the exposed portion of the Composite canvas behind the + // StyledText control matches the background color of the StyledText + // control. + + Color textBackground = text.getBackground(); + text.getParent().setBackground(textBackground); + + // Scroll the StyledText widget to the bottommost position. + + text.setSelectionRange(text.getCharCount(), 0); + text.showSelection(); + + // Tell the parent object to redraw itself. This erases any partial + // line of text that might be left visible where the parent object is + // now exposed. This call only happens if the size needed to be changed, + // so it should not cause any flicker. + + text.getParent().redraw(); + } + + // If we are in a TELNET connection and we know the dimensions of the terminal, + // we give the size information to the TELNET connection object so it can + // communicate it to the TELNET server. If we are in a serial connection, + // there is nothing we can do to tell the remote host about the size of the + // terminal. + + ITerminalConnector telnetConnection = terminal.getTerminalConnection(); + + if (telnetConnection != null && widthInColumns != 0 && heightInLines != 0) { + telnetConnection.setTerminalSize(widthInColumns, heightInLines); + } + } + + /** + * This method computes the the pixel width of a character in the current + * font. The Font object representing the font in the Terminal view doesn't + * provide the pixel width of the characters (even for a fixed width font). + * Instead, we get the pixel coordinates of the upper left corner of the + * bounding boxes for two adjacent characters on the same line and subtract + * the X coordinate of one from the X coordinate of the other. Simple, no? + */ + protected void computeCharacterPixelWidth() { + // We can't assume there is any text in the terminal, so make sure there's at + // least two characters. + + text.replaceTextRange(0, 0, " "); //$NON-NLS-1$ + + Point firstCharLocation = text.getLocationAtOffset(0); + Point secondCharLocation = text.getLocationAtOffset(1); + + characterPixelWidth = secondCharLocation.x - firstCharLocation.x; + + text.replaceTextRange(0, 3, ""); //$NON-NLS-1$ + } + + /** + * This method deletes as many of the topmost lines of text as needed to + * keep the total number of lines of text in the Terminal view less than or + * equal to the limit configured in the preferences. If no limit is + * configured, this method does nothing. + */ + protected void deleteTopmostLines() { + if (!fLimitOutput) + return; + + // Compute the number of lines to delete, but don't do anything if there are + // fewer lines in the terminal than the height of the terminal in lines. + + int totalLineCount = text.getLineCount(); + + if (totalLineCount <= heightInLines) + return; + + int bufferLineLimit = fBufferLineLimit; + + // Don't allow the user to set the buffer line limit to less than the height of + // the terminal in lines. + + if (bufferLineLimit <= heightInLines) + bufferLineLimit = heightInLines + 1; + + int linesToDelete = totalLineCount - bufferLineLimit; + + // Delete the lines. A small optimization here: don't do anything unless + // there's at least 5 lines to delete. + + if (linesToDelete >= 5) + text.replaceTextRange(0, text.getOffsetAtLine(linesToDelete), ""); //$NON-NLS-1$ + } + + /** + * This method returns the absolute line number of the line containing the + * cursor. The very first line of text (even if it is scrolled off the + * screen) is absolute line number 0. + * + * @return The absolute line number of the line containing the cursor. + */ + protected int absoluteCursorLine() { + return text.getLineAtOffset(text.getCaretOffset()); + } + + /** + * This method returns the relative line number of the line comtaining 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. + */ + protected int relativeCursorLine() { + int totalLines = text.getLineCount(); + + if (totalLines <= heightInLines) + return text.getLineAtOffset(text.getCaretOffset()); + + return absoluteCursorLine() - totalLines + heightInLines; + } + + /** + * This method converts a visible line number (i.e., line 0 is the topmost + * visible line if the terminal is scrolled all the way down, and line + * number heightInLines - 1 is the bottommost visible line if the terminal + * is scrolled all the way down) to a line number as known to the StyledText + * widget. + */ + protected int absoluteLine(int visibleLineNumber) { + int totalLines = text.getLineCount(); + + if (totalLines <= heightInLines) + return visibleLineNumber; + + return totalLines - heightInLines + visibleLineNumber; + } + + /** + * This method returns a String containing count ch + * characters. + * + * @return A String containing count ch characters. + */ + protected String generateString(char ch, int count) { + char[] chars = new char[count]; + + for (int i = 0; i < chars.length; ++i) + chars[i] = ch; + + return new String(chars); + } + + /** + * This method moves the cursor to the specified line and column. Parameter + * targetLine 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. + */ + protected void moveCursor(int targetLine, int targetColumn) { + // Don't allow out of range target line and column values. + + if (targetLine < 0) + targetLine = 0; + if (targetLine >= heightInLines) + targetLine = heightInLines - 1; + + if (targetColumn < 0) + targetColumn = 0; + if (targetColumn >= widthInColumns) + targetColumn = widthInColumns - 1; + + // First, find out if we need to append newlines to the end of the text. This + // is necessary if there are fewer total lines of text than visible screen + // lines and the target line is below the bottommost line of text. + + int totalLines = text.getLineCount(); + + if (totalLines < heightInLines && targetLine >= totalLines) + text.append(generateString('\n', heightInLines - totalLines)); + + // Next, compute the offset of the start of the target line. + + int targetLineStartOffset = text + .getOffsetAtLine(absoluteLine(targetLine)); + + // Next, find how many characters are in the target line. Be careful not to + // index off the end of the StyledText widget. + + int nextLineNumber = absoluteLine(targetLine + 1); + int targetLineLength; + + if (nextLineNumber >= totalLines) { + // The target line is the bottommost line of text. + + targetLineLength = text.getCharCount() - targetLineStartOffset; + } else { + // The target line is not the bottommost line of text, so compute its + // length by subtracting the start offset of the target line from the start + // offset of the following line. + + targetLineLength = text.getOffsetAtLine(nextLineNumber) + - targetLineStartOffset - 1; + } + + // Find out if we can just move the cursor without having to insert spaces at + // the end of the target line. + + if (targetColumn >= targetLineLength) { + // The target line is not long enough to just move the cursor, so we have + // to append spaces to it before positioning the cursor. + + int spacesToAppend = targetColumn - targetLineLength; + + text.replaceTextRange(targetLineStartOffset + targetLineLength, 0, + generateString(' ', spacesToAppend)); + } + + // Now position the cursor. + + text.setCaretOffset(targetLineStartOffset + targetColumn); + + cursorColumn = targetColumn; + } + + /** + * This method moves the cursor down lines lines, but won't move the + * cursor past the bottom of the screen. This method does not cause any + * scrolling. + */ + protected void moveCursorDown(int lines) { + moveCursor(relativeCursorLine() + lines, cursorColumn); + } + + /** + * This method moves the cursor up lines lines, but won't move the + * cursor past the top of the screen. This method does not cause any + * scrolling. + */ + protected void moveCursorUp(int lines) { + moveCursor(relativeCursorLine() - lines, cursorColumn); + } + + /** + * This method moves the cursor forward columns columns, but won't + * move the cursor past the right edge of the screen, nor will it move the + * cursor onto the next line. This method does not cause any scrolling. + */ + protected void moveCursorForward(int columnsToMove) { + moveCursor(relativeCursorLine(), cursorColumn + columnsToMove); + } + + /** + * This method moves the cursor backward columnsToMove columns, but + * won't move the cursor past the left edge of the screen, nor will it move + * the cursor onto the previous line. This method does not cause any + * scrolling. + */ + protected void moveCursorBackward(int columnsToMove) { + // We don't call moveCursor() here, because this is optimized for backward + // cursor motion on a single line. + + if (columnsToMove > cursorColumn) + columnsToMove = cursorColumn; + + text.setCaretOffset(text.getCaretOffset() - columnsToMove); + + cursorColumn -= columnsToMove; + } + + protected int getBufferLineLimit() { + return fBufferLineLimit; + } + + protected void setBufferLineLimit(int bufferLineLimit) { + fBufferLineLimit = bufferLineLimit; + } + + protected boolean isLimitOutput() { + return fLimitOutput; + } + + protected void setLimitOutput(boolean limitOutput) { + fLimitOutput = limitOutput; + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/ITelnetSettings.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/ITelnetSettings.java new file mode 100644 index 00000000000..61d3c9a8eb3 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/ITelnetSettings.java @@ -0,0 +1,12 @@ +package org.eclipse.tm.terminal.internal.telnet; + +import org.eclipse.tm.terminal.ISettingsStore; + +public interface ITelnetSettings { + String getHost(); + int getNetworkPort(); + int getTimeout(); + String getStatusString(String strConnected); + void load(ISettingsStore store); + void save(ISettingsStore store); +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/NetworkPortMap.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/NetworkPortMap.java new file mode 100644 index 00000000000..f864c802031 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/NetworkPortMap.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.telnet; + +import java.util.ArrayList; +import java.util.List; + +public class NetworkPortMap { + public static final String PROP_NAMETGTCONST = "tgtcons"; //$NON-NLS-1$ + public static final String PROP_NAMETELNET = "telnet"; //$NON-NLS-1$ + public static final String PROP_VALUENET = "1233"; //$NON-NLS-1$ + public static final String PROP_VALUETGTCONST = "1232"; //$NON-NLS-1$ + public static final String PROP_VALUETELNET = "23"; //$NON-NLS-1$ + String[][] fPortMap=new String[][] { + // portName, port + {PROP_NAMETGTCONST, PROP_VALUETGTCONST}, + {PROP_NAMETELNET, PROP_VALUETELNET} + }; + public String getDefaultNetworkPort() { + return PROP_VALUETELNET; + } + public String findPortName(String strPort) { + for (int i = 0; i < fPortMap.length; i++) { + if(fPortMap[i][1].equals(strPort)) + return fPortMap[i][0]; + } + return null; + } + public String findPort(String strPortName) { + for (int i = 0; i < fPortMap.length; i++) { + if(fPortMap[i][0].equals(strPortName)) + return fPortMap[i][1]; + } + return null; + } + public List getNameTable() { + List names=new ArrayList(); + for (int i = 0; i < fPortMap.length; i++) { + names.add(fPortMap[i][0]); + } + return names; + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetCodes.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetCodes.java similarity index 98% rename from org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetCodes.java rename to org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetCodes.java index c696786c753..da29a14ef35 100644 --- a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/TelnetCodes.java +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetCodes.java @@ -10,7 +10,7 @@ * *******************************************************************************/ -package org.eclipse.tm.terminal; +package org.eclipse.tm.terminal.internal.telnet; /** * This interface defines symbolic constants for numeric TELNET protocol command and diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnectWorker.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnectWorker.java new file mode 100644 index 00000000000..e4b967926ba --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnectWorker.java @@ -0,0 +1,69 @@ +package org.eclipse.tm.terminal.internal.telnet; + +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; + +class TelnetConnectWorker extends Thread { + private final ITerminalControl fControl; + private final TelnetConnector fConn; + protected TelnetConnectWorker(TelnetConnector conn,ITerminalControl control) { + fControl = control; + fConn = conn; + fControl.setState(TerminalState.CONNECTING); + } + public void run() { + try { + int nTimeout = fConn.getTelnetSettings().getTimeout() * 1000; + String strHost = fConn.getTelnetSettings().getHost(); + int nPort = fConn.getTelnetSettings().getNetworkPort(); + InetSocketAddress address = new InetSocketAddress(strHost, nPort); + Socket socket=new Socket(); + + socket.connect(address, nTimeout); + + // This next call causes reads on the socket to see TCP urgent data + // inline with the rest of the non-urgent data. Without this call, TCP + // urgent data is silently dropped by Java. This is required for + // TELNET support, because when the TELNET server sends "IAC DM", the + // IAC byte is TCP urgent data. If urgent data is silently dropped, we + // only see the DM, which looks like an ISO Latin-1 '�' character. + + socket.setOOBInline(true); + + fConn.setSocket(socket); + + TelnetConnection connection=new TelnetConnection(fConn, socket); + socket.setKeepAlive(true); + fConn.setTelnetConnection(connection); + connection.start(); + fControl.setState(TerminalState.CONNECTED); + + } catch (UnknownHostException ex) { + String txt="Unknown host: " + ex.getMessage(); //$NON-NLS-1$ + connectFailed(txt,"Unknown host: " + ex.getMessage() + "\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } catch (SocketTimeoutException socketTimeoutException) { + connectFailed(socketTimeoutException.getMessage(), "Connection Error!\n" + socketTimeoutException.getMessage()); //$NON-NLS-1$ + } catch (ConnectException connectException) { + connectFailed(connectException.getMessage(),"Connection refused!"); //$NON-NLS-1$ + } catch (Exception exception) { + Logger.logException(exception); + + connectFailed(exception.getMessage(),""); //$NON-NLS-1$ + } + } + + private void connectFailed(String terminalText, String msg) { + Logger.log(terminalText); + fControl.displayTextInTerminal(terminalText); + fConn.cleanSocket(); + fControl.setState(TerminalState.CLOSED); + fControl.setMsg(msg); + } +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnection.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnection.java new file mode 100644 index 00000000000..ec5d3082a35 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnection.java @@ -0,0 +1,684 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.telnet; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketException; + +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; + +/** + * This class encapsulates a TELNET connection to a remote server. It processes + * incoming TELNET protocol data and generates outbound TELNET protocol data. It + * also manages two sets of TelnetOption objects: one for the local endpoint and + * one for the remote endpoint. + *

+ * + * IMPORTANT: Understanding this code requires understanding the TELNET protocol + * and TELNET option processing, as defined in the RFCs listed below. + *

+ * + * @author Fran Litterio (francis.litterio@windriver.com) + * + * @see RFC 854 + * @see RFC 855 + * @see RFC 856 + * @see RFC 857 + * @see RFC 858 + * @see RFC 859 + * @see RFC 860 + * @see RFC 861 + * @see RFC 1091 + * @see RFC 1096 + * @see RFC 1073 + * @see RFC 1079 + * @see RFC 1143 + * @see RFC 1572 + */ +public class TelnetConnection extends Thread implements TelnetCodes { + /** + * TELNET connection state: Initial state. + */ + protected static final int STATE_INITIAL = 0; + + /** + * TELNET connection state: Last byte processed was IAC code. code. + */ + protected static final int STATE_IAC_RECEIVED = 1; + + /** + * TELNET connection state: Last byte processed was WILL code. code. + */ + protected static final int STATE_WILL_RECEIVED = 2; + + /** + * TELNET connection state: Last byte processed was WONT code. + */ + protected static final int STATE_WONT_RECEIVED = 3; + + /** + * TELNET connection state: Last byte processed was DO code. + */ + protected static final int STATE_DO_RECEIVED = 4; + + /** + * TELNET connection state: Last byte processed was DONT code. + */ + protected static final int STATE_DONT_RECEIVED = 5; + + /** + * TELNET connection state: Last byte processed was SB. + */ + protected static final int STATE_SUBNEGOTIATION_STARTED = 6; + + /** + * TELNET connection state: Currently receiving sub-negotiation data. + */ + protected static final int STATE_RECEIVING_SUBNEGOTIATION = 7; + + /** + * Size of buffer for processing data received from remote endpoint. + */ + protected static final int BUFFER_SIZE = 2048; + + /** + * Holds raw bytes received from the remote endpoint, prior to any TELNET + * protocol processing. + */ + protected byte[] rawBytes = new byte[BUFFER_SIZE]; + + /** + * Holds incoming network data after the TELNET protocol bytes have been + * processed and removed. + */ + protected byte[] processedBytes = new byte[BUFFER_SIZE]; + + /** + * This field holds a StringBuffer containing text recently received from + * the remote endpoint (after all TELNET protocol bytes have been processed + * and removed). + */ + protected StringBuffer processedStringBuffer = new StringBuffer(BUFFER_SIZE); + + /** + * Holds the current state of the TELNET protocol processor. + */ + protected int telnetState = STATE_INITIAL; + + /** + * This field is true if the remote endpoint is a TELNET server, false if + * not. We set this to true if and only if the remote endpoint sends + * recognizable TELNET protocol data. We do not assume that the remote + * endpoint is a TELNET server just because it is listening on port 23. This + * allows us to successfully connect to a TELNET server listening on a port + * other than 23. + *

+ * + * When this field first changes from false to true, we send all WILL or DO + * commands to the remote endpoint. + *

+ * + * @see #telnetServerDetected() + */ + protected boolean remoteIsTelnetServer = false; + + /** + * An array of TelnetOption objects representing the local endpoint's TELNET + * options. The array is indexed by the numeric TELNET option code. + */ + protected TelnetOption[] localOptions = new TelnetOption[256]; + + /** + * An array of TelnetOption objects representing the remote endpoint's + * TELNET options. The array is indexed by the numeric TELNET option code. + */ + protected TelnetOption[] remoteOptions = new TelnetOption[256]; + + /** + * An array of bytes that holds the TELNET subnegotiation command most + * recently received from the remote endpoint. This array does _not_ include + * the leading IAC SB bytes, nor does it include the trailing IAC SE bytes. + * The first byte of this array is always a TELNET option code. + */ + protected byte[] receivedSubnegotiation = new byte[128]; + + /** + * This field holds the index into array {@link receivedSubnegotiation} of + * the next unused byte. This is used by method + * {@link #processTelnetProtocol(int)} when the state machine is in states + * {@link #STATE_SUBNEGOTIATION_STARTED} and {@link + * STATE_RECEIVING_SUBNEGOTIATION}. + */ + protected int nextSubnegotiationByteIndex = 0; + + /** + * This field is true if an error occurs while processing a subnegotiation + * command. + * + * @see #processTelnetProtocol(int) + */ + protected boolean ignoreSubnegotiation = false; + + /** + * This field holds the width of the Terminal screen in columns. + */ + protected int width = 0; + + /** + * This field holds the height of the Terminal screen in rows. + */ + protected int height = 0; + + /** + * This field holds a reference to the {@link ITerminalControl} singleton. + */ + protected TelnetConnector terminalControl; + + /** + * This method holds the Socket object for the TELNET connection. + */ + protected Socket socket; + + /** + * This field holds a reference to an {@link InputStream} object used to + * receive data from the remote endpoint. + */ + protected InputStream inputStream; + + /** + * This field holds a reference to an {@link OutputStream} object used to + * send data to the remote endpoint. + */ + protected OutputStream outputStream; + + /** + * UNDER CONSTRUCTION + */ + protected boolean localEcho = true; + + /** + * This constructor just initializes some internal object state from its + * arguments. + */ + public TelnetConnection(TelnetConnector terminalControl, Socket socket) throws IOException { + super(); + + Logger.log("entered"); //$NON-NLS-1$ + + this.terminalControl = terminalControl; + this.socket = socket; + + inputStream = socket.getInputStream(); + outputStream = socket.getOutputStream(); + + initializeOptions(); + } + + /** + * Returns true if the TCP connection represented by this object is + * connected, false otherwise. + */ + public boolean isConnected() { + return socket != null && socket.isConnected(); + } + + /** + * Returns true if the TCP connection represented by this object is + * connected and the remote endpoint is a TELNET server, false otherwise. + */ + public boolean isRemoteTelnetServer() { + return remoteIsTelnetServer; + } + + /** + * This method sets the terminal width and height to the supplied values. If + * either new value differs from the corresponding old value, we initiate a + * NAWS subnegotiation to inform the remote endpoint of the new terminal + * size. + */ + public void setTerminalSize(int newWidth, int newHeight) { + Logger.log("Setting new size: width = " + newWidth + ", height = " + newHeight); //$NON-NLS-1$ //$NON-NLS-2$ + if (!isConnected() || !isRemoteTelnetServer()) + return; + boolean sizeChanged = false; + + if (newWidth != width || newHeight != height) + sizeChanged = true; + + width = newWidth; + height = newHeight; + + if (sizeChanged && remoteIsTelnetServer && localOptions[TELNET_OPTION_NAWS].isEnabled()) { + Integer[] sizeData = { new Integer(width), new Integer(height) }; + + localOptions[TELNET_OPTION_NAWS].sendSubnegotiation(sizeData); + } + } + + /** + * Returns true if local echoing is enabled for this TCP connection, false + * otherwise. + */ + public boolean localEcho() { + return localEcho; + } + + private void writeToTerminal(String string) { + terminalControl.writeToTerminal(string); + } + + /** + * This method runs in its own thread. It reads raw bytes from the TELNET + * connection socket, processes any TELNET protocol bytes (and removes + * them), and passes the remaining bytes to a TerminalDisplay object for + * display. + */ + public void run() { + Logger.log("Entered"); //$NON-NLS-1$ + + try { + while (socket.isConnected()) { + int nRawBytes = inputStream.read(rawBytes); + + if (nRawBytes == -1) { + // End of input on inputStream. + Logger.log("End of input reading from socket!"); //$NON-NLS-1$ + + // Announce to the user that the remote endpoint has closed the + // connection. + + writeToTerminal("\r"+TelnetMessages.CONNECTION_CLOSED_BY_FOREIGN_HOST+"\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ + + // Tell the ITerminalControl object that the connection is + // closed. + terminalControl.setState(TerminalState.CLOSED); + break; + } else { + Logger.log("Received " + nRawBytes + " bytes: '" + //$NON-NLS-1$ //$NON-NLS-2$ + new String(rawBytes, 0, nRawBytes) + "'"); //$NON-NLS-1$ + + // Process any TELNET protocol data that we receive. Don't + // send any TELNET protocol data until we are sure the remote + // endpoint is a TELNET server. + + int nProcessedBytes = processTelnetProtocol(nRawBytes); + + if (nProcessedBytes > 0) { + writeToTerminal(new String(processedBytes, 0, nProcessedBytes)); + } + } + } + } catch (SocketException ex) { + String message = ex.getMessage(); + + // A "socket closed" exception is normal here. It's caused by the + // user clicking the disconnect button on the Terminal view toolbar. + + if (message != null && !message.equals("socket closed")) //$NON-NLS-1$ + { + Logger.logException(ex); + } + } catch (Exception ex) { + Logger.logException(ex); + } + } + + /** + * This method initializes the localOptions[] and remoteOptions[] arrays so + * that they contain references to TelnetOption objects representing our + * desired state for each option. The goal is to achieve server-side + * echoing, suppression of Go Aheads, and to send the local terminal type + * and size to the remote endpoint. + */ + protected void initializeOptions() { + // First, create all the TelnetOption objects in the "undesired" state. + + for (int i = 0; i < localOptions.length; ++i) { + localOptions[i] = new TelnetOption((byte) i, false, true, outputStream); + } + + for (int i = 0; i < localOptions.length; ++i) { + remoteOptions[i] = new TelnetOption((byte) i, false, false, outputStream); + } + + // Next, set some of the options to the "desired" state. The options we + // desire to be enabled are as follows: + // + // TELNET Option Desired for Desired for + // Name and Code Local Endpoint Remote Endpoint + // --------------------- -------------- --------------- + // Echo (1) No Yes + // Suppress Go Ahead (3) Yes Yes + // Terminal Type (24) Yes Yes + // NAWS (31) Yes Yes + // + // All other options remain in the "undesired" state, and thus will be + // disabled (since either endpoint can force any option to be disabled by simply + // answering WILL with DONT and DO with WONT). + + localOptions[TELNET_OPTION_ECHO].setDesired(false); + remoteOptions[TELNET_OPTION_ECHO].setDesired(true); + + localOptions[TELNET_OPTION_SUPPRESS_GA].setDesired(true); + remoteOptions[TELNET_OPTION_SUPPRESS_GA].setDesired(true); + + localOptions[TELNET_OPTION_TERMINAL_TYPE].setDesired(true); + remoteOptions[TELNET_OPTION_TERMINAL_TYPE].setDesired(true); + + localOptions[TELNET_OPTION_NAWS].setDesired(true); + remoteOptions[TELNET_OPTION_NAWS].setDesired(true); + } + + /** + * Process TELNET protocol data contained in the first count bytes + * of rawBytes. This function preserves its state between calls, + * because a multi-byte TELNET command might be split between two (or more) + * calls to this function. The state is preserved in field telnetState. + * This function implements an FSA that recognizes TELNET option codes. + * TELNET option state is stored in instances of {@link TelnetOption}. + * TELNET option subnegotiation is delegated to instances of TelnetOption. + * + * @return The number of bytes remaining in the buffer after removing all + * TELNET protocol bytes. + */ + protected int processTelnetProtocol(int count) { + // This is too noisy to leave on all the time. + // Logger.log("Processing " + count + " bytes of data."); + + int nextProcessedByte = 0; + + for (int byteIndex = 0; byteIndex < count; ++byteIndex) { + // It is possible for control to flow through the below code such + // that nothing happens. This happens when array rawBytes[] contains no + // TELNET protocol data. + + byte inputByte = rawBytes[byteIndex]; + + switch (telnetState) { + case STATE_INITIAL: + if (inputByte == TELNET_IAC) { + telnetState = STATE_IAC_RECEIVED; + } else { + // It's not an IAC code, so just append it to + // processedBytes. + + processedBytes[nextProcessedByte++] = rawBytes[byteIndex]; + } + break; + + case STATE_IAC_RECEIVED: + switch (inputByte) { + case TELNET_IAC: + // Two IAC bytes in a row are translated into one byte with + // the + // value 0xff. + + processedBytes[nextProcessedByte++] = (byte) 0xff; + telnetState = STATE_INITIAL; + break; + + case TELNET_WILL: + telnetState = STATE_WILL_RECEIVED; + break; + + case TELNET_WONT: + telnetState = STATE_WONT_RECEIVED; + break; + + case TELNET_DO: + telnetState = STATE_DO_RECEIVED; + break; + + case TELNET_DONT: + telnetState = STATE_DONT_RECEIVED; + break; + + case TELNET_SB: + telnetState = STATE_SUBNEGOTIATION_STARTED; + break; + + // Commands to consume and ignore. + + // Data Mark (DM). This is sent by a TELNET server following an + // IAC sent as TCP urgent data. It should cause the client to + // skip all not yet processed non-TELNET-protocol data preceding the + // DM byte. However, Java 1.4.x has no way to inform clients of + // class Socket that urgent data is available, so we simply ignore the + // "IAC DM" command. Since the IAC is sent as TCP urgent data, + // the Socket must be put into OOB-inline mode via a call to + // setOOBInline(true), otherwise the IAC is silently dropped by + // Java and only the DM arrives (leaving the user to see a + // spurious ISO Latin-1 character). + case TELNET_DM: + + case TELNET_NOP: // No-op. + case TELNET_GA: // Go Ahead command. Meaningless on a full-duplex link. + case TELNET_IP: // Interupt Process command. Server should never send this. + case TELNET_AO: // Abort Output command. Server should never send this. + case TELNET_AYT: // Are You There command. Server should never send this. + case TELNET_EC: // Erase Character command. Server should never send this. + case TELNET_EL: // Erase Line command. Server should never send this. + telnetState = STATE_INITIAL; + break; + + default: + // Unrecognized command! This should never happen. + Logger.log("processTelnetProtocol: UNRECOGNIZED TELNET PROTOCOL COMMAND: " + //$NON-NLS-1$ + inputByte); + telnetState = STATE_INITIAL; + break; + } + break; + + // For the next four cases, WILL and WONT commands affect the state + // of remote options, and DO and DONT commands affect the state of + // local options. + + case STATE_WILL_RECEIVED: + Logger.log("Received WILL " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + remoteOptions[inputByte].handleWill(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_WONT_RECEIVED: + Logger.log("Received WONT " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + remoteOptions[inputByte].handleWont(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_DO_RECEIVED: + Logger.log("Received DO " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + localOptions[inputByte].handleDo(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_DONT_RECEIVED: + Logger.log("Received DONT " + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + localOptions[inputByte].handleDont(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_SUBNEGOTIATION_STARTED: + Logger.log("Starting subnegotiation for option " + //$NON-NLS-1$ + localOptions[inputByte].optionName() + "."); //$NON-NLS-1$ + + // First, zero out the array of received subnegotiation butes. + + for (int i = 0; i < receivedSubnegotiation.length; ++i) + receivedSubnegotiation[i] = 0; + + // Forget about any previous subnegotiation errors. + + ignoreSubnegotiation = false; + + // Then insert this input byte into the array and enter state + // STATE_RECEIVING_SUBNEGOTIATION, where we will gather the + // remaining subnegotiation bytes. + + nextSubnegotiationByteIndex = 0; + receivedSubnegotiation[nextSubnegotiationByteIndex++] = inputByte; + telnetState = STATE_RECEIVING_SUBNEGOTIATION; + break; + + case STATE_RECEIVING_SUBNEGOTIATION: + if (inputByte == TELNET_IAC) { + // Handle double IAC bytes. From RFC 855: "if parameters + // in an option 'subnegotiation' include a byte with a value + // of 255, it is necessary to double this byte in accordance + // the general TELNET rules." + + if (nextSubnegotiationByteIndex > 0 + && receivedSubnegotiation[nextSubnegotiationByteIndex - 1] == TELNET_IAC) { + // The last input byte we received in this + // subnegotiation was IAC, so this is a double IAC. Leave the previous IAC + // in the receivedSubnegotiation[] array and drop the current + // one (thus translating a double IAC into a single IAC). + + Logger.log("Double IAC in subnegotiation translated into single IAC."); //$NON-NLS-1$ + break; + } + + // Append the IAC byte to receivedSubnegotiation[]. If there + // is no room for the IAC byte, it overwrites the last byte, + // because we need to know when the subnegotiation ends, and that is + // marked by an "IAC SE" command. + + if (nextSubnegotiationByteIndex < receivedSubnegotiation.length) { + receivedSubnegotiation[nextSubnegotiationByteIndex++] = inputByte; + } else { + receivedSubnegotiation[receivedSubnegotiation.length - 1] = inputByte; + } + break; + } + + // Handle an "IAC SE" command, which marks the end of the + // subnegotiation. An SE byte by itself might be a legitimate + // part of the subnegotiation data, so don't do anything unless the SE + // is immediately preceded by an IAC. + + if (inputByte == TELNET_SE && receivedSubnegotiation[nextSubnegotiationByteIndex - 1] == TELNET_IAC) { + Logger.log("Found SE code marking end of subnegotiation."); //$NON-NLS-1$ + + // We are done receiving the subnegotiation command. Now + // process it. We always use the option object stored in array + // localOptions[] to process the received subnegotiation. + // This is an arbitrary decision, but it is sufficient for handling + // options TERMINAL-TYPE and NAWS, which are the only options that + // we subnegotiate (presently). If, in the future,subnegotiations + // need to be handled by option objects stored in both + // localOptions[] and remoteOptions[], then some mechanism + // to choose the correct option object must be implemented. + // + // Also, if ignoreSubnegotiation is true, there was an error + // while receiving the subnegotiation, so we must not process the + // command, and instead just return to the initial state. + + if (!ignoreSubnegotiation) { + // Remove the trailing IAC byte from + // receivedSubnegotiation[]. + + receivedSubnegotiation[nextSubnegotiationByteIndex - 1] = 0; + + int subnegotiatedOption = receivedSubnegotiation[0]; + + localOptions[subnegotiatedOption].handleSubnegotiation(receivedSubnegotiation, + nextSubnegotiationByteIndex); + } else { + Logger.log("NOT CALLING handleSubnegotiation() BECAUSE OF ERRORS!"); //$NON-NLS-1$ + } + + // Return to the initial state. + + telnetState = STATE_INITIAL; + } + + // Check whether the receivedSubnegotiation[] array is full. + + if (nextSubnegotiationByteIndex >= receivedSubnegotiation.length) { + // This should not happen. Array receivedSubnegotiation can + // hold 128 bytes, and no TELNET option that we perform + // subnegotiation for requires that many bytes in a subnegotiation command. + // In the interest of robustness, we handle this case by ignoring all + // remaining subnegotiation bytes until we receive the IAC SE + // command that ends the subnegotiation. Also, we set + // ignoreSubnegotiation to true to prevent a call to + // handleSubnegotiation() when the IAC SE command arrives. + + Logger.log("SUBNEGOTIATION BUFFER FULL!"); //$NON-NLS-1$ + ignoreSubnegotiation = true; + } else { + Logger.log("Recording subnegotiation byte " + (inputByte & 0xff)); //$NON-NLS-1$ + + receivedSubnegotiation[nextSubnegotiationByteIndex++] = inputByte; + } + break; + + default: + // This should _never_ happen! If it does, it means there is a + // bug in this FSA. For robustness, we return to the initial state. + + Logger.log("INVALID TELNET STATE: " + telnetState); //$NON-NLS-1$ + telnetState = STATE_INITIAL; + break; + } + } + + // Return the number of bytes of processed data (i.e., number of bytes + // of raw data minus TELNET control bytes). This value can be zero. + + return nextProcessedByte; + } + + /** + * This method is called whenever we receive a valid TELNET protocol command + * from the remote endpoint. When it is called for the first time for this + * connection, we negotiate all options that we desire to be enabled. + *

+ * + * This method does not negotiate options that we do not desire to be + * enabled, because all options are initially disabled. + *

+ */ + protected void telnetServerDetected() { + if (!remoteIsTelnetServer) { + // This block only executes once per TelnetConnection instance. + + localEcho = false; + + Logger.log("Detected TELNET server."); //$NON-NLS-1$ + + remoteIsTelnetServer = true; + + for (int i = 0; i < localOptions.length; ++i) { + if (localOptions[i].isDesired()) { + localOptions[i].negotiate(); + } + } + + for (int i = 0; i < remoteOptions.length; ++i) { + if (remoteOptions[i].isDesired()) { + remoteOptions[i].negotiate(); + } + } + } + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnector.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnector.java new file mode 100644 index 00000000000..dbbeb176736 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetConnector.java @@ -0,0 +1,144 @@ +/** + * + */ +package org.eclipse.tm.terminal.internal.telnet; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import org.eclipse.tm.terminal.ISettingsPage; +import org.eclipse.tm.terminal.ISettingsStore; +import org.eclipse.tm.terminal.ITerminalConnector; +import org.eclipse.tm.terminal.ITerminalControl; +import org.eclipse.tm.terminal.Logger; +import org.eclipse.tm.terminal.TerminalState; + +public class TelnetConnector implements ITerminalConnector { + private OutputStream fOutputStream; + private InputStream fInputStream; + private Socket fSocket; + private ITerminalControl fControl; + private TelnetConnection fTelnetConnection; + private final TelnetSettings fSettings; + public TelnetConnector() { + this(new TelnetSettings()); + } + public String getId() { + return getClass().getName(); + } + public TelnetConnector(TelnetSettings settings) { + fSettings=settings; + } + public void connect(ITerminalControl control) { + Logger.log("entered."); //$NON-NLS-1$ + fControl=control; + TelnetConnectWorker worker = new TelnetConnectWorker(this,control); + worker.start(); + } + public void disconnect() { + Logger.log("entered."); //$NON-NLS-1$ + + if (getSocket() != null) { + try { + getSocket().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + if (getInputStream() != null) { + try { + getInputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + if (getOutputStream() != null) { + try { + getOutputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + cleanSocket(); + setState(TerminalState.CLOSED); + } + public boolean isLocalEcho() { + if(fTelnetConnection!=null) + return false; + return fTelnetConnection.localEcho(); + } + public void setTerminalSize(int newWidth, int newHeight) { + if(fTelnetConnection!=null) + fTelnetConnection.setTerminalSize(newWidth, newHeight); + + } + public InputStream getInputStream() { + return fInputStream; + } + public OutputStream getOutputStream() { + return fOutputStream; + } + private void setInputStream(InputStream inputStream) { + fInputStream = inputStream; + } + private void setOutputStream(OutputStream outputStream) { + fOutputStream = outputStream; + } + Socket getSocket() { + return fSocket; + } + + /** + * sets the socket to null + */ + void cleanSocket() { + fSocket=null; + setInputStream(null); + setOutputStream(null); + } + + void setSocket(Socket socket) throws IOException { + if(socket==null) { + cleanSocket(); + } else { + fSocket = socket; + setInputStream(socket.getInputStream()); + setOutputStream(socket.getOutputStream()); + } + + } + public void setTelnetConnection(TelnetConnection connection) { + fTelnetConnection=connection; + } + public void writeToTerminal(String txt) { + fControl.writeToTerminal(txt); + + } + public void setState(TerminalState state) { + fControl.setState(state); + + } + public ITelnetSettings getTelnetSettings() { + return fSettings; + } + public ISettingsPage makeSettingsPage() { + return new TelnetSettingsPage(fSettings); + } + public String getStatusString(String strConnected) { + return fSettings.getStatusString(strConnected); + } + public void load(ISettingsStore store) { + fSettings.load(store); + + } + public void save(ISettingsStore store) { + fSettings.save(store); + } + public boolean isInstalled() { + return true; + } +} \ No newline at end of file diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.java new file mode 100644 index 00000000000..793ec7e7202 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.telnet; + +import org.eclipse.osgi.util.NLS; + +public class TelnetMessages extends NLS { + static { + NLS.initializeMessages(TelnetMessages.class.getName(), TelnetMessages.class); + } + public static String CONNTYPE_NETWORK; + public static String PORT; + public static String HOST; + public static String CONNECTION_CLOSED_BY_FOREIGN_HOST; + public static String TIMEOUT; + + } diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.properties b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.properties new file mode 100644 index 00000000000..1ad647e083e --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetMessages.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2006 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: +# Wind River Systems, Inc. - initial implementation +# +############################################################################### +CONNTYPE_NETWORK = Network +PORT = Port +HOST = Host +CONNECTION_CLOSED_BY_FOREIGN_HOST= Connection closed by foreign host. +TIMEOUT = Timeout diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetOption.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetOption.java new file mode 100644 index 00000000000..5e6ebb4eeeb --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetOption.java @@ -0,0 +1,698 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + + +package org.eclipse.tm.terminal.internal.telnet; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; + +import org.eclipse.tm.terminal.Logger; + +/** + * This class represents a single TELNET protocol option at one endpoint of a TELNET + * connection. This class encapsulates the endpoint associated with the option (local + * or remote), the current state of the option (enabled or disabled), the desired state + * of the option, the current state of the negotiation, an OutputStream that allows + * communication with the remote endpoint, and the number of negotiations that have + * started within this connection.

+ * + * In addition to encapsulating the above state, this class performs option negotiation + * to attempt to achieve the desired option state. For some options, this class also + * performs option sub-negotiation.

+ * + * IMPORTANT: Understanding this code requires understanding the TELNET protocol and + * TELNET option processing.

+ * + * @author Fran Litterio (francis.litterio@windriver.com) + */ +class TelnetOption implements TelnetCodes +{ + /** + * This array of Strings maps an integer TELNET option code value to the symbolic + * name of the option. Array elements of the form "?" represent unassigned option + * values. + */ + protected static final String[] optionNames = + { + "BINARY", // 0 //$NON-NLS-1$ + "ECHO", // 1 //$NON-NLS-1$ + "RECONNECTION", // 2 //$NON-NLS-1$ + "SUPPRESS GO AHEAD", // 3 //$NON-NLS-1$ + "MSG SIZE NEGOTIATION", // 4 //$NON-NLS-1$ + "STATUS", // 5 //$NON-NLS-1$ + "TIMING MARK", // 6 //$NON-NLS-1$ + "REMOTE CTRL TRANS+ECHO", // 7 //$NON-NLS-1$ + "OUTPUT LINE WIDTH", // 8 //$NON-NLS-1$ + "OUTPUT PAGE SIZE", // 9 //$NON-NLS-1$ + "OUTPUT CR DISPOSITION", // 10 //$NON-NLS-1$ + "OUTPUT HORIZ TABSTOPS", // 11 //$NON-NLS-1$ + "OUTPUT HORIZ TAB DISPOSITION", // 12 //$NON-NLS-1$ + "OUTPUT FORMFEED DISPOSITION", // 13 //$NON-NLS-1$ + "OUTPUT VERTICAL TABSTOPS", // 14 //$NON-NLS-1$ + "OUTPUT VT DISPOSITION", // 15 //$NON-NLS-1$ + "OUTPUT LF DISPOSITION", // 16 //$NON-NLS-1$ + "EXTENDED ASCII", // 17 //$NON-NLS-1$ + "LOGOUT", // 18 //$NON-NLS-1$ + "BYTE MACRO", // 19 //$NON-NLS-1$ + "DATA ENTRY TERMINAL", // 20 //$NON-NLS-1$ + "SUPDUP", // 21 //$NON-NLS-1$ + "SUPDUP OUTPUT", // 22 //$NON-NLS-1$ + "SEND LOCATION", // 23 //$NON-NLS-1$ + "TERMINAL TYPE", // 24 //$NON-NLS-1$ + "END OF RECORD", // 25 //$NON-NLS-1$ + "TACACS USER IDENTIFICATION", // 26 //$NON-NLS-1$ + "OUTPUT MARKING", // 27 //$NON-NLS-1$ + "TERMINAL LOCATION NUMBER", // 28 //$NON-NLS-1$ + "3270 REGIME", // 29 //$NON-NLS-1$ + "X.3 PAD", // 30 //$NON-NLS-1$ + "NEGOTIATE ABOUT WINDOW SIZE", // 31 //$NON-NLS-1$ + "TERMINAL SPEED", // 32 //$NON-NLS-1$ + "REMOTE FLOW CONTROL", // 33 //$NON-NLS-1$ + "LINEMODE", // 34 //$NON-NLS-1$ + "X DISPLAY LOCATION", // 35 //$NON-NLS-1$ + "ENVIRONMENT OPTION", // 36 //$NON-NLS-1$ + "AUTHENTICATION OPTION", // 37 //$NON-NLS-1$ + "ENCRYPTION OPTION", // 38 //$NON-NLS-1$ + "NEW ENVIRONMENT OPTION", // 39 //$NON-NLS-1$ + "TN3270E", // 40 //$NON-NLS-1$ + "XAUTH", // 41 //$NON-NLS-1$ + "CHARSET", // 42 //$NON-NLS-1$ + "REMOTE SERIAL PORT", // 43 //$NON-NLS-1$ + "COM PORT CONTROL OPTION", // 44 //$NON-NLS-1$ + "SUPPRESS LOCAL ECHO", // 45 //$NON-NLS-1$ + "START TLS", // 46 //$NON-NLS-1$ + "KERMIT", // 47 //$NON-NLS-1$ + "SEND URL", // 48 //$NON-NLS-1$ + "FORWARD X", // 49 //$NON-NLS-1$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 50 ... //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", // ... 137 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ + "TELOPT PRAGMA LOGON", // 138 //$NON-NLS-1$ + "TELOPT SSPI LOGON", // 139 //$NON-NLS-1$ + "TELOPT PRAGMA HEARTBEAT", // 140 //$NON-NLS-1$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", // 141 ... //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", "?", "?", "?", "?", "?", "?", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$ //$NON-NLS-8$ //$NON-NLS-9$ //$NON-NLS-10$ + "?", "?", "?", "?", // ... 254 //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + "EXTENDED OPTIONS LIST" // 255 //$NON-NLS-1$ + }; + + /** + * Negotiation state: Negotiation not yet started for this option.

+ * + * This constant and the others having similar names represent the states of a + * finite state automaton (FSA) that tracks the negotiation state of this option. + * The initial state is NEGOTIATION_NOT_STARTED. The state machine is as follows + * (with transitions labelled with letters in parentheses):

+ * + *

+     *     NEGOTIATION_NOT_STARTED -----> {@link #NEGOTIATION_IN_PROGRESS}
+     *                         |    (A)      |        ^
+     *                      (C)|          (B)|        |(D)
+     *                         |             V        |
+     *                         +--------> {@link #NEGOTIATION_DONE}
+     * 

+ * + * Once the FSA leaves state NEGOTIATION_NOT_STARTED, it never returns to that + * state. Transition A happens when the local endpoint sends an option command + * before receiving a command for the same option from the remote endpoint.

+ * + * Transition B happens when the local endpoint receives a reply to an option + * command sent earlier by the local endpoint. Receipt of that reply terminates + * the negotiation.

+ * + * Transition D happens after negotiation is done and "something changes" (see the + * RFCs for the definition of "something changes"). Either endpoint can + * re-negotiate an option after a previous negotiation, but only if some external + * influence (such as the user or the OS) causes it to do so. Re-negotiation must + * start more than {@link #NEGOTIATION_IGNORE_DURATION} milliseconds after the FSA + * enters state NEGOTIATION_DONE or it will be ignored. This is how this client + * prevents negotiation loops.

+ * + * Transition C happens when the local endpoint receives an option command from the + * remote endpoint before sending a command for the same option. In that case, the + * local endpoint replies immediately with an option command and the negotitation + * terminates.

+ * + * Some TELNET servers (e.g., the Solaris server), after sending WILL and receiving + * DONT, will reply with a superfluous WONT. Any such superfluous option command + * received from the remote endpoint while the option's FSA is in state + * {@link #NEGOTIATION_DONE} will be ignored by the local endpoint. + */ + protected static final int NEGOTIATION_NOT_STARTED = 0; + + /** Negotiation state: Negotiation is in progress for this option. */ + protected static final int NEGOTIATION_IN_PROGRESS = 1; + + /** Negotiation state: Negotiation has terminated for this option. */ + protected static final int NEGOTIATION_DONE = 2; + + /** + * The number of milliseconds following the end of negotiation of this option + * before which the remote endpoint can re-negotiate the option. Any option + * command received from the remote endpoint before this time passes is ignored. + * This is used to prevent option negotiation loops. + * + * @see #ignoreNegotiation() + * @see #negotiationCompletionTime + */ + protected static final int NEGOTIATION_IGNORE_DURATION = 30000; + + /** + * This field holds the current negotiation state for this option. + */ + protected int negotiationState = NEGOTIATION_NOT_STARTED; + + /** + * This field holds the time when negotiation of this option most recently + * terminated (i.e., entered state {@link #NEGOTIATION_DONE}). This is used to + * determine whether an option command received from the remote endpoint after + * negotiation has terminated for this option is to be ignored or interpreted as + * the start of a new negotiation. + * + * @see #NEGOTIATION_IGNORE_DURATION + */ + protected Date negotiationCompletionTime = new Date(0); + + /** + * Holds the total number of negotiations that have completed for this option. + */ + protected int negotiationCount = 0; + + /** + * Holds the integer code representing the option. + */ + protected byte option = 0; + + /** + * Holds the OutputStream object that allows data to be sent to the remote endpoint + * of the TELNET connection. + */ + protected OutputStream outputStream; + + /** + * True if this option is for the local endpoint, false for the remote endpoint. + */ + protected boolean local = true; + + /** + * This field is true if the option is enabled, false if it is disabled. All + * options are initially disabled until they are negotiated to be enabled.

+ */ + protected boolean enabled = false; + + /** + * This field is true if the client desires the option to be enabled, false if the + * client desires the option to be disabled. This field does not represent the + * remote's endpoints desire (as expressed via WILL and WONT commands) -- it + * represnet the local endpoint's desire.

+ * + * @see #setDesired(boolean) + */ + protected boolean desired = false; + + /** + * Constructor.

+ * + * @param option The integer code of this option. + * @param desired Whether we desire this option to be enabled. + * @param local Whether this option is for the local or remote endpoint. + * @param outputStream A stream used to negotiate with the remote endpoint. + */ + TelnetOption(byte option, boolean desired, boolean local, + OutputStream outputStream) { + this.option = option; + this.desired = desired; + this.local = local; + this.outputStream = outputStream; + } + + /** + * @return Returns a String containing the name of the TELNET option specified in + * parameter option. + */ + public String optionName() { + return optionNames[option]; + } + + /** + * Returns true if this option is enabled, false if it is disabled.

+ * + * @return Returns true if this option is enabled, false if it is disabled. + */ + public boolean isEnabled() { + return enabled; + } + + /** + * Enables this option if newValue is true, otherwise disables this + * option.

+ * + * @param newValue True if this option is to be enabled, false otherwise. + */ + public void setEnabled(boolean newValue) { + Logger.log("Enabling " + (local ? "local" : "remote") + " option " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + optionName()); + enabled = newValue; + } + + /** + * Returns true if the local endpoint desires this option to be enabled, false if + * not. It is not an error for the value returned by this method to differ from + * the value returned by isEnabled(). The value returned by this method can change + * over time, reflecting the local endpoint's changing desire regarding the + * option.

+ * + * NOTE: Even if this option represents a remote endpoint option, the return value + * of this method represents the local endpint's desire regarding the remote + * option.

+ * + * @return Returns true if the local endpoint desires this option to be enabled, + * false if not. + */ + public boolean isDesired() { + return desired; + } + + /** + * Sets our desired value for this option. Note that the option can be desired + * when enabled is false, and the option can be undesired when + * enabled is true, though the latter state should not persist, since either + * endpoint can disable any option at any time.

+ * + * @param newValue True if we desire this option to be enabled, false if + * we desire this option to be disabled. + */ + public void setDesired(boolean newValue) { + if (newValue) + Logger.log("Setting " + (local ? "local" : "remote") + " option " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + optionName() + " as desired."); //$NON-NLS-1$ + + desired = newValue; + } + + /** + * Call this method to request that negotiation begin for this option. This method + * does nothing if negotiation for this option has already started or is already + * complete. If negotiation has not yet started for this option and the local + * endpoint desires this option to be enabled, then we send a WILL or DO command to + * the remote endpoint. + */ + public void negotiate() { + if (negotiationState == NEGOTIATION_NOT_STARTED && desired) { + if (local) { + Logger + .log("Starting negotiation for local option " + optionName()); //$NON-NLS-1$ + sendWill(); + } else { + Logger + .log("Starting negotiation for remote option " + optionName()); //$NON-NLS-1$ + sendDo(); + } + + negotiationState = NEGOTIATION_IN_PROGRESS; + } + } + + /** + * This method is called whenever we receive a WILL command from the remote + * endpoint. + */ + public void handleWill() { + if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) { + Logger + .log("Ignoring superfluous WILL command from remote endpoint."); //$NON-NLS-1$ + return; + } + + if (negotiationState == NEGOTIATION_IN_PROGRESS) { + if (desired) { + // We sent DO and server replied with WILL. Enable the option, and end + // this negotiation. + + enabled = true; + Logger.log("Enabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } else { + // This should never happen! We sent DONT and the server replied with + // WILL. Bad server. No soup for you. Disable the option, and end + // this negotiation. + + Logger.log("Server answered DONT with WILL!"); //$NON-NLS-1$ + enabled = false; + Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } + } else { + if (desired) { + // Server sent WILL, so we reply with DO. Enable the option, and end + // this negotiation. + + sendDo(); + enabled = true; + Logger.log("Enabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } else { + // Server sent WILL, so we reply with DONT. Disable the option, and + // end this negotiation. + + sendDont(); + enabled = false; + Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } + } + } + + /** + * Handles a WONT command sent by the remote endpoint for this option. The value + * of desired doesn't matter in this method, because the remote endpoint is + * forcing the option to be disabled. + */ + public void handleWont() { + if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) { + Logger + .log("Ignoring superfluous WONT command from remote endpoint."); //$NON-NLS-1$ + return; + } + + if (negotiationState == NEGOTIATION_IN_PROGRESS) { + // We sent DO or DONT and server replied with WONT. Disable the + // option, and end this negotiation. + + enabled = false; + Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } else { + // Server sent WONT, so we reply with DONT. Disable the option, and + // end this negotiation. + + sendDont(); + enabled = false; + Logger.log("Disabling remote option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } + } + + /** + * Handles a DO command sent by the remote endpoint for this option. + */ + public void handleDo() { + if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) { + Logger.log("Ignoring superfluous DO command from remote endpoint."); //$NON-NLS-1$ + return; + } + + if (negotiationState == NEGOTIATION_IN_PROGRESS) { + if (desired) { + // We sent WILL and server replied with DO. Enable the option, and end + // this negotiation. + + enabled = true; + Logger.log("Enabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } else { + // We sent WONT and server replied with DO. This should never happen! + // Bad server. No soup for you. Disable the option, and end this + // negotiation. + + Logger.log("Server answered WONT with DO!"); //$NON-NLS-1$ + enabled = false; + Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } + } else { + if (desired) { + // Server sent DO, so we reply with WILL. Enable the option, and end + // this negotiation. + + sendWill(); + enabled = true; + Logger.log("Enabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } else { + // Server sent DO, so we reply with WONT. Disable the option, and end + // this negotiation. + + sendWont(); + enabled = false; + Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } + } + } + + /** + * Handles a DONT command sent by the remote endpoint for this option. The value + * of desired doesn't matter in this method, because the remote endpoint is + * forcing the option to be disabled. + */ + public void handleDont() { + if (negotiationState == NEGOTIATION_DONE && ignoreNegotiation()) { + Logger + .log("Ignoring superfluous DONT command from remote endpoint."); //$NON-NLS-1$ + return; + } + + if (negotiationState == NEGOTIATION_IN_PROGRESS) { + // We sent WILL or WONT and server replied with DONT. Disable the + // option, and end this negotiation. + + enabled = false; + Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } else { + // Server sent DONT, so we reply with WONT. Disable the option, and end + // this negotiation. + + sendWont(); + enabled = false; + Logger.log("Disabling local option " + optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + endNegotiation(); + } + } + + /** + * This method handles a subnegotiation command received from the remote endpoint. + * Currently, the only subnegotiation we handle is when the remote endpoint + * commands us to send our terminal type (which is "ansi"). + * + * @param subnegotiationData An array of bytes containing a TELNET + * subnegotiation command received from the + * remote endpoint. + * @param count The number of bytes in array + * subnegotiationData to examine. + */ + public void handleSubnegotiation(byte[] subnegotiationData, int count) { + switch (option) { + case TELNET_OPTION_TERMINAL_TYPE: + if (subnegotiationData[1] != TELNET_SEND) { + // This should never happen! + Logger + .log("Invalid TERMINAL-TYPE subnegotiation command from remote endpoint: " + //$NON-NLS-1$ + (subnegotiationData[1] & 0xff)); + break; + } + + // Tell the remote endpoint our terminal type is "ansi" using this sequence + // of TELNET protocol bytes: + // + // IAC SB TERMINAL-TYPE IS a n s i IAC SE + + byte[] terminalTypeData = { TELNET_IAC, TELNET_SB, + TELNET_OPTION_TERMINAL_TYPE, TELNET_IS, (byte) 'a', + (byte) 'n', (byte) 's', (byte) 'i', TELNET_IAC, TELNET_SE }; + + try { + outputStream.write(terminalTypeData); + } catch (IOException ex) { + Logger.log("IOException sending TERMINAL-TYPE subnegotiation!"); //$NON-NLS-1$ + Logger.logException(ex); + } + break; + + default: + // This should never happen! + Logger + .log("SHOULD NOT BE REACHED: Called for option " + optionName()); //$NON-NLS-1$ + break; + } + } + + /** + * This method sends a subnegotiation command to the remote endpoint. + * + * @param subnegotiationData An array of Objects holding data to be used + * when generating the outbound subnegotiation + * command. + */ + public void sendSubnegotiation(Object[] subnegotiationData) { + switch (option) { + case TELNET_OPTION_NAWS: + // Get the width and height of the view and send it to the remote + // endpoint using this sequence of TELNET protocol bytes: + // + // IAC SB NAWS + // IAC SE + + byte[] NAWSData = { TELNET_IAC, TELNET_SB, TELNET_OPTION_NAWS, 0, + 0, 0, 0, TELNET_IAC, TELNET_SE }; + int width = ((Integer) subnegotiationData[0]).intValue(); + int height = ((Integer) subnegotiationData[1]).intValue(); + + NAWSData[3] = (byte) ((width >>> 8) & 0xff); // High order byte of width. + NAWSData[4] = (byte) (width & 0xff); // Low order byte of width. + NAWSData[5] = (byte) ((height >>> 8) & 0xff); // High order byte of height. + NAWSData[6] = (byte) (height & 0xff); // Low order byte of height. + + Logger + .log("sending terminal size to remote endpoint: width = " + width + //$NON-NLS-1$ + ", height = " + height + "."); //$NON-NLS-1$ //$NON-NLS-2$ + + // This final local variable is a hack to get around the fact that inner + // classes cannot reference a non-final local variable in a lexically + // enclosing scope. + + final byte[] NAWSDataFinal = NAWSData; + + // Send the NAWS data in a new thread. The current thread is the display + // thread, and calls to write() can block, but blocking the display thread + // is _bad_ (it hangs the GUI). + + new Thread() { + public void run() { + try { + outputStream.write(NAWSDataFinal); + } catch (IOException ex) { + Logger.log("IOException sending NAWS subnegotiation!"); //$NON-NLS-1$ + Logger.logException(ex); + } + } + }.start(); + break; + + default: + // This should never happen! + Logger + .log("SHOULD NOT BE REACHED: Called for option " + optionName()); //$NON-NLS-1$ + break; + } + } + + /** + * This method returns true if there has not yet been any negotiation of this + * option. + * + * @return Returns true if there has not yet been any negotiation of this option. + */ + protected boolean notYetNegotiated() { + return negotiationState == NEGOTIATION_NOT_STARTED; + } + + /** + * This method terminates the current negotiation and records the time at which the + * negotiation terminated. + */ + protected void endNegotiation() { + Logger.log("Ending negotiation #" + negotiationCount + " for " + //$NON-NLS-1$ //$NON-NLS-2$ + (local ? "local" : "remote") + " option " + optionName()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + negotiationState = NEGOTIATION_DONE; + negotiationCompletionTime.setTime(System.currentTimeMillis()); + ++negotiationCount; + } + + /** + * This method determines whether or not to ignore what appears to be a new + * negotiation initiated by the remote endpoint. This is needed because some + * TELNET servers send superfluous option commands that a naive client might + * interpret as the start of a new negotiation. If the superfluous command is not + * ignored, an option negotiation loop can result (which is bad). For details + * about the superfluous commands sent by some servers, see the documentation for + * {@link #NEGOTIATION_NOT_STARTED}.

+ * + * The current implementation of this method returns true if the new negotiation + * starts within NEGOTIATION_IGNORE_DURATION seconds of the end of the previous + * negotiation of this option.

+ * + * @return Returns true if the new negotiation should be ignored, false if not. + */ + protected boolean ignoreNegotiation() { + return (System.currentTimeMillis() - negotiationCompletionTime + .getTime()) > NEGOTIATION_IGNORE_DURATION; + } + + /** + * Sends a DO command to the remote endpoint for this option. + */ + protected void sendDo() { + Logger.log("Sending DO " + optionName()); //$NON-NLS-1$ + sendCommand(TELNET_DO); + } + + /** + * Sends a DONT command to the remote endpoint for this option. + */ + protected void sendDont() { + Logger.log("Sending DONT " + optionName()); //$NON-NLS-1$ + sendCommand(TELNET_DONT); + } + + /** + * Sends a WILL command to the remote endpoint for this option. + */ + protected void sendWill() { + Logger.log("Sending WILL " + optionName()); //$NON-NLS-1$ + sendCommand(TELNET_WILL); + } + + /** + * Sends a WONT command to the remote endpoint for this option. + */ + protected void sendWont() { + Logger.log("Sending WONT " + optionName()); //$NON-NLS-1$ + sendCommand(TELNET_WONT); + } + + /** + * This method sends a WILL/WONT/DO/DONT command to the remote endpoint for this + * option. + */ + protected void sendCommand(byte command) { + byte[] data = { TELNET_IAC, 0, 0 }; + + data[1] = command; + data[2] = option; + + try { + outputStream.write(data); + } catch (IOException ex) { + Logger.log("IOException sending command " + command); //$NON-NLS-1$ + Logger.logException(ex); + } + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetProperties.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetProperties.java new file mode 100644 index 00000000000..2903698a223 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetProperties.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.telnet; + + + +public class TelnetProperties { + private final NetworkPortMap fNetworkPortMap; + private final String fDefaultHost; + private final String fDefaultNetworkPort; + + public TelnetProperties() { + fNetworkPortMap = new NetworkPortMap(); + fDefaultNetworkPort = fNetworkPortMap.getDefaultNetworkPort(); + fDefaultHost = ""; //$NON-NLS-1$ + + } + + public String getDefaultHost() { + return fDefaultHost; + } + + public String getDefaultNetworkPort() { + return fDefaultNetworkPort; + } + + public NetworkPortMap getNetworkPortMap() { + // TODO Auto-generated method stub + return fNetworkPortMap; + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettings.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettings.java new file mode 100644 index 00000000000..9fa7dbc8758 --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettings.java @@ -0,0 +1,89 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.telnet; + +import org.eclipse.tm.terminal.ISettingsStore; +import org.eclipse.tm.terminal.ITerminalConnector; + +public class TelnetSettings implements ITelnetSettings { + protected String fHost; + protected String fNetworkPort; + protected String fTimeout; + private final TelnetProperties fProperties=new TelnetProperties(); + public String getHost() { + return fHost; + } + + public void setHost(String strHost) { + fHost = strHost; + } + + public String getNetworkPortString() { + return fNetworkPort; + } + + public int getNetworkPort() { + try { + return Integer.parseInt(fNetworkPort); + } catch (NumberFormatException numberFormatException) { + return 1313; + } + } + + public void setNetworkPort(String strNetworkPort) { + fNetworkPort = strNetworkPort; + } + + public String getStatusString(String strConnected) { + return " (" + //$NON-NLS-1$ + getHost() + ":" + //$NON-NLS-1$ + getNetworkPortString() + " - " + //$NON-NLS-1$ + strConnected + ")"; //$NON-NLS-1$ + } + + + public ITerminalConnector makeConnector() { + return new TelnetConnector(this); + } + + + public void load(ISettingsStore store) { + fHost = store.get("Host", fProperties.getDefaultHost());//$NON-NLS-1$ + fNetworkPort = store.get("NetworkPort", fProperties.getDefaultNetworkPort());//$NON-NLS-1$ + } + + + public void save(ISettingsStore store) { + store.put("Host", fHost);//$NON-NLS-1$ + store.put("NetworkPort", fNetworkPort);//$NON-NLS-1$ + } + + + public TelnetProperties getProperties() { + return fProperties; + } + public int getTimeout() { + try { + return Integer.parseInt(fTimeout); + } catch (NumberFormatException numberFormatException) { + return 10; + } + } + public String getTimeoutString() { + return fTimeout; + } + + public void setTimeout(String timeout) { + fTimeout = timeout; + } +} diff --git a/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettingsPage.java b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettingsPage.java new file mode 100644 index 00000000000..203e851c82a --- /dev/null +++ b/org.eclipse.tm.terminal/src/org/eclipse/tm/terminal/internal/telnet/TelnetSettingsPage.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2006 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: + * Wind River Systems, Inc. - initial implementation + * + *******************************************************************************/ + +package org.eclipse.tm.terminal.internal.telnet; + +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.terminal.ISettingsPage; + +public class TelnetSettingsPage implements ISettingsPage { + private Text fHostText; + private Combo fNetworkPortCombo; + private Text fTimeout; + private final TelnetSettings fTerminalSettings; + + public TelnetSettingsPage(TelnetSettings settings) { + fTerminalSettings=settings; + } + public void saveSettings() { + fTerminalSettings.setHost(fHostText.getText()); + fTerminalSettings.setTimeout(fTimeout.getText()); + fTerminalSettings.setNetworkPort(getNetworkPort()); + } + + public void loadSettings() { + if(fTerminalSettings!=null) { + setHost(fTerminalSettings.getHost()); + setTimeout(fTerminalSettings.getTimeoutString()); + setNetworkPort(fTerminalSettings.getNetworkPortString()); + } + } + private void setHost(String strHost) { + if(strHost==null) + strHost=""; //$NON-NLS-1$ + fHostText.setText(strHost); + + } + private void setTimeout(String timeout) { + if(timeout==null || timeout.length()==0) + timeout="5"; //$NON-NLS-1$ + fTimeout.setText(timeout); + + } + private void setNetworkPort(String strNetworkPort) { + String strPortName = getNetworkPortMap().findPortName(strNetworkPort); + if(strPortName==null) + strPortName=""; //$NON-NLS-1$ + int nIndex = fNetworkPortCombo.indexOf(strPortName); + + if (nIndex == -1) { + fNetworkPortCombo.setText(strNetworkPort); + } else { + fNetworkPortCombo.select(nIndex); + } + } + private String getNetworkPort() { + return getNetworkPortMap().findPort(fNetworkPortCombo.getText()); + } + private NetworkPortMap getNetworkPortMap() { + return fTerminalSettings.getProperties().getNetworkPortMap(); + } + + public boolean validateSettings() { + return true; + } + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(2, false); + GridData gridData = new GridData(GridData.FILL_HORIZONTAL); + + composite.setLayout(gridLayout); + composite.setLayoutData(gridData); + + // Add label + Label ctlLabel = new Label(composite, SWT.RIGHT); + ctlLabel.setText(TelnetMessages.HOST + ":"); //$NON-NLS-1$ + + // Add control + gridData = new GridData(GridData.FILL_HORIZONTAL); + fHostText = new Text(composite, SWT.BORDER); + fHostText.setLayoutData(gridData); + + // Add label + ctlLabel = new Label(composite, SWT.RIGHT); + ctlLabel.setText(TelnetMessages.PORT + ":"); //$NON-NLS-1$ + + // Add control + gridData = new GridData(GridData.FILL_HORIZONTAL); + fNetworkPortCombo = new Combo(composite, SWT.DROP_DOWN); + + fNetworkPortCombo.setLayoutData(gridData); + + List table = getNetworkPortMap().getNameTable(); + Collections.sort(table); + loadCombo(fNetworkPortCombo, table); + + new Label(composite, SWT.RIGHT).setText(TelnetMessages.TIMEOUT + ":"); //$NON-NLS-1$ + fTimeout = new Text(composite, SWT.BORDER); + fTimeout.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + loadSettings(); + } + private void loadCombo(Combo ctlCombo, List table) { + for (Iterator iter = table.iterator(); iter.hasNext();) { + String label = (String) iter.next(); + ctlCombo.add(label); + } + } + + public String getName() { + return TelnetMessages.CONNTYPE_NETWORK; + } + +}