diff --git a/site/category.xml b/site/category.xml new file mode 100644 index 00000000000..58e44b5cb64 --- /dev/null +++ b/site/category.xml @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TM Terminal Features + + + + + TM Terminal SDK Features + + + + + TM Terminal Examples, Tests + + + + + + + Dependencies + + + diff --git a/site/pom.xml b/site/pom.xml new file mode 100755 index 00000000000..f699ca1c9d2 --- /dev/null +++ b/site/pom.xml @@ -0,0 +1,25 @@ + + + + + 4.0.0 + + org.eclipse.tm + tm-parent + 4.5.100-SNAPSHOT + + + org.eclipse.tm.rse + org.eclipse.tm.site + 4.5.102-SNAPSHOT + eclipse-repository + diff --git a/terminal/.gitignore b/terminal/.gitignore new file mode 100644 index 00000000000..0751d5c9ae4 --- /dev/null +++ b/terminal/.gitignore @@ -0,0 +1,17 @@ +# ignore various emacs droppings +*~ +\#*\# + +# . +workspace +debug-workspace + +# Ignored throughout the whole tree +bin/ +target/ +coverage/ +artifacts/ +/ManifestValidationResult.html + +# MacOSX +.DS_Store diff --git a/terminal/CONTRIBUTING b/terminal/CONTRIBUTING new file mode 100644 index 00000000000..871327d9889 --- /dev/null +++ b/terminal/CONTRIBUTING @@ -0,0 +1,50 @@ +Contributing to Target Management Terminal +========================================== + +Thanks for your interest in this project. + +Project description: +-------------------- + +The Target Management Terminal is a lightweight VT100 terminal implementation. The project provides a re-usable terminal widget, +a set of predefined terminal connectors (i.e. SSH and local shell) and a view managing the terminal sessions. + +Developer resources: +-------------------- + +Source Repositories: + +You can use the code from these repositories to experiment, test, build, create patches, issue pull requests, etc. This project uses Gerrit Code Review; please see contributing via Gerrit (https://wiki.eclipse.org/Gerrit). + +tm/org.eclipse.tm.terminal - Target Management Terminal + Clone: https://git.eclipse.org/r/tm/org.eclipse.tm.terminal + Browse Repository: http://git.eclipse.org/c/tm/org.eclipse.tm.terminal.git + Review with Gerrit: https://git.eclipse.org/r/p/tm/org.eclipse.tm.terminal + +Contributor License Agreement: +------------------------------ + +Before your contribution can be accepted by the project, you need to create and electronically sign the Eclipse Foundation Contributor License Agreement (CLA). + +- http://www.eclipse.org/legal/CLA.php + +Contact: +-------- + +Contact the project developers via the project's "dev" list. + +- https://dev.eclipse.org/mailman/listinfo/tm-dev + +Search for bugs: +---------------- + +This project uses Bugzilla to track ongoing development and issues. + +- https://bugs.eclipse.org/bugs/buglist.cgi?bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&classification=Tools&component=Terminal&list_id=11564722&product=Target%20Management&query_format=advanced + +Create a new bug: +----------------- + +Be sure to search for existing bugs before you create another one. Remember that contributions are always welcome! + +- https://bugs.eclipse.org/bugs/enter_bug.cgi?product=Target%20Management&component=Terminal diff --git a/terminal/admin/.gitignore b/terminal/admin/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/terminal/admin/.gitignore @@ -0,0 +1 @@ +/target diff --git a/terminal/admin/.project b/terminal/admin/.project new file mode 100644 index 00000000000..fd600362323 --- /dev/null +++ b/terminal/admin/.project @@ -0,0 +1,38 @@ + + + Administration (TM Terminal) + + + + + + + + + + CONTRIBUTING + 1 + PARENT-1-PROJECT_LOC/CONTRIBUTING + + + pom.xml + 1 + PARENT-1-PROJECT_LOC/pom.xml + + + readme.txt + 1 + PARENT-1-PROJECT_LOC/readme.txt + + + terminals.psf + 1 + PARENT-1-PROJECT_LOC/terminals.psf + + + toplevel.gitignore + 1 + PARENT-1-PROJECT_LOC/.gitignore + + + diff --git a/terminal/admin/findbugs-exclude.xml b/terminal/admin/findbugs-exclude.xml new file mode 100644 index 00000000000..7e5962c7154 --- /dev/null +++ b/terminal/admin/findbugs-exclude.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/admin/pom-build.xml b/terminal/admin/pom-build.xml new file mode 100644 index 00000000000..4da5f4544ea --- /dev/null +++ b/terminal/admin/pom-build.xml @@ -0,0 +1,136 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-config + 4.5.100-SNAPSHOT + pom-config.xml + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + pom + TM Terminal, Maven Build Master + + + + + org.eclipse.tycho + tycho-maven-plugin + + + org.eclipse.tycho + target-platform-configuration + + + org.eclipse.tycho + tycho-source-plugin + + + + + + + findbugs + + + + org.codehaus.mojo + findbugs-maven-plugin + + + + + + static-checks + + + + org.codehaus.mojo + findbugs-maven-plugin + + + org.apache.maven.plugins + maven-pmd-plugin + + + + + + tests + + + + org.eclipse.tycho + target-platform-configuration + + + + + + p2-installable-unit + org.eclipse.platform.ide + 0.0.0 + + + eclipse-feature + org.eclipse.sdk + 0.0.0 + + + eclipse-feature + org.eclipse.cdt.platform + 0.0.0 + + + eclipse-feature + org.eclipse.remote + 0.0.0 + + + eclipse-feature + org.eclipse.swtbot.eclipse + 0.0.0 + + + + + + + org.jacoco + jacoco-maven-plugin + + + + prepare-agent + + + + org.eclipse.tm.terminal* + + + + + + + + + + + + diff --git a/terminal/admin/pom-config.xml b/terminal/admin/pom-config.xml new file mode 100644 index 00000000000..21a4dba63e9 --- /dev/null +++ b/terminal/admin/pom-config.xml @@ -0,0 +1,94 @@ + + + + + 4.0.0 + + + org.eclipse.tm + tm-parent + 4.5.100-SNAPSHOT + ../../ + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-config + pom + TM Terminal, Maven Configuration Master + + + + Eclipse Public License + https://www.eclipse.org/legal/epl-2.0/ + repo + + All rights reserved. + + This program and the accompanying materials are made + available under the terms of the Eclipse Public License 2.0 + which accompanies this distribution, and is available at + https://www.eclipse.org/legal/epl-2.0/ + + + + + + Eclipse Foundation + http://www.eclipse.org/ + + + + + ${env.WORKSPACE}/admin + UTF-8 + + + false + file + true + + development + ${project.artifactId}.zip + /home/data/httpd/download.eclipse.org/tm/terminal/builds/${terminal-stream}/nightly + scm:git:git://git.eclipse.org/gitroot/tm/org.eclipse.tm.git + + + + + + + org.apache.maven.plugins + maven-pmd-plugin + 3.8 + + utf-8 + 100 + 1.7 + xml + false + + **/UbcCheck.java + + + + + + cpd-check + + + + + + + + diff --git a/terminal/admin/target-defs/eclipse-4.8.x-photon.target b/terminal/admin/target-defs/eclipse-4.8.x-photon.target new file mode 100644 index 00000000000..39952d614f2 --- /dev/null +++ b/terminal/admin/target-defs/eclipse-4.8.x-photon.target @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/admin/target-defs/tm-baseline.target b/terminal/admin/target-defs/tm-baseline.target new file mode 100644 index 00000000000..e2b7e52557e --- /dev/null +++ b/terminal/admin/target-defs/tm-baseline.target @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/.project new file mode 100644 index 00000000000..ea0d993407f --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.cdtserial.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/build.properties new file mode 100644 index 00000000000..c33f2d71b1e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/feature.properties new file mode 100644 index 00000000000..a90186dd5a5 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2017, 2018 QNX Software Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# QNX Software Systems - Initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Serial Connector Extensions + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A serial line connector for the Terminal + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2017 QNX Software Systems and others.\ +All rights reserved. This program and the accompanying materials\ +are made available under the terms of the Eclipse Public License 2.0\ +which accompanies this distribution, and is available at\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/feature.xml new file mode 100644 index 00000000000..b198559013e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/feature.xml @@ -0,0 +1,42 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/pom.xml new file mode 100644 index 00000000000..bf559ad5aea --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.cdtserial.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/.project new file mode 100644 index 00000000000..b870ea2d162 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.cdtserial.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/build.properties new file mode 100644 index 00000000000..c33f2d71b1e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/feature.properties new file mode 100644 index 00000000000..67f7b2eb272 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2017, 2018 QNX Software Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# QNX Software Systems - Initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Serial Connector Extensions, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A serial line connector for the Terminal + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2017 QNX Software Systems and others.\ +All rights reserved. This program and the accompanying materials\ +are made available under the terms of the Eclipse Public License 2.0\ +which accompanies this distribution, and is available at\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/feature.xml new file mode 100644 index 00000000000..570add7fec7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/feature.xml @@ -0,0 +1,50 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/pom.xml new file mode 100644 index 00000000000..a02406184db --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.cdtserial.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.cdtserial.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/.project new file mode 100644 index 00000000000..2b177926011 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.local.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/build.properties new file mode 100644 index 00000000000..c33f2d71b1e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/feature.properties new file mode 100644 index 00000000000..9acef2d3f8a --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Local Connector Extensions + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A connector implementation for the Local Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2003, 2017 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/feature.xml new file mode 100644 index 00000000000..02ff5e2e12e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/feature.xml @@ -0,0 +1,58 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.feature/p2.inf b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/p2.inf new file mode 100644 index 00000000000..aa2b22ba1aa --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/p2.inf @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2014, 2015 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +# Make the org.eclipse.cdt.native feature dependency "optional" since it didn't +# exist in CDT 8.3 and we can also work on top of CDT 8.3. + +# The real dependencies are all properly managed via p2.inf in the +# org.eclipse.tm.terminal.connector.process/META-INF/p2.inf file. +# The only benefit of requesting the feature here is that it allow pulling in +# additional fragments that we are not aware of in the bundle's p2.inf. + +requires.0.namespace = org.eclipse.equinox.p2.iu +requires.0.name = org.eclipse.cdt.native.feature.group +requires.0.greedy = true +requires.0.optional = true diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/pom.xml new file mode 100644 index 00000000000..215d3563580 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.local.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/.project new file mode 100644 index 00000000000..e85d50ff010 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.local.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/build.properties new file mode 100644 index 00000000000..c33f2d71b1e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/feature.properties new file mode 100644 index 00000000000..e3339ab9f3b --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Local Connector Extensions, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A connector implementation for the Local Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2003, 2017 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/feature.xml new file mode 100644 index 00000000000..efdefed91c7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/feature.xml @@ -0,0 +1,56 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/pom.xml new file mode 100644 index 00000000000..ac14412495e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.local.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.local.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/.project new file mode 100644 index 00000000000..678a8ee6245 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.remote.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/build.properties new file mode 100644 index 00000000000..de0d7aecfa8 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/build.properties @@ -0,0 +1,11 @@ +############################################################################### +# Copyright (c) 2015, 2018 IBM Corp. and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/feature.properties new file mode 100644 index 00000000000..d1943459533 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/feature.properties @@ -0,0 +1,35 @@ +############################################################################### +# Copyright (c) 2015, 2018 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal via Remote API Connector Extensions + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A Terminal Connector using the org.eclipse.remote API. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2015, 2017 IBM Corporation and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/feature.xml new file mode 100644 index 00000000000..fe0d35a4280 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/feature.xml @@ -0,0 +1,55 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/pom.xml new file mode 100644 index 00000000000..f4665073bf2 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.remote.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/.project new file mode 100644 index 00000000000..f63833fdb66 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.remote.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/build.properties new file mode 100644 index 00000000000..38d32796c6d --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/build.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2015, 2018 IBM Corp. and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### + +bin.includes = feature.xml,\ + feature.properties + +generate.plugin@org.eclipse.tm.terminal.remote.source=org.eclipse.tm.terminal.remote diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/feature.properties new file mode 100644 index 00000000000..24a2e7d8681 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/feature.properties @@ -0,0 +1,35 @@ +############################################################################### +# Copyright (c) 2015, 2018 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal via Remote API Connector Extensions, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=An remote connector implementation for the Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2015, 2017 IBM Corporation and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/feature.xml new file mode 100644 index 00000000000..54556b9ec4a --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/feature.xml @@ -0,0 +1,49 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/pom.xml new file mode 100644 index 00000000000..3dee0088fac --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.remote.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.remote.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/.project new file mode 100644 index 00000000000..c96f85db4dd --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.ssh.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/build.properties new file mode 100644 index 00000000000..8e3ce5326b9 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/build.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +############################################################################### +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/feature.properties new file mode 100644 index 00000000000..2c8e307d916 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal SSH Connector Extensions + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=An SSH connector implementation for the Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2000, 2017 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/feature.xml new file mode 100644 index 00000000000..7943d715af7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/feature.xml @@ -0,0 +1,54 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/pom.xml new file mode 100644 index 00000000000..61100c70ff7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.ssh.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/.project new file mode 100644 index 00000000000..3a7e0685dd4 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.ssh.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/build.properties new file mode 100644 index 00000000000..8e3ce5326b9 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/build.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +############################################################################### +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/feature.properties new file mode 100644 index 00000000000..b650b956f92 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal SSH Connector Extensions, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=An SSH connector implementation for the Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2000, 2017 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/feature.xml new file mode 100644 index 00000000000..6376b5b2d55 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/feature.xml @@ -0,0 +1,50 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/pom.xml new file mode 100644 index 00000000000..e829e93606c --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.ssh.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.ssh.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/.project new file mode 100644 index 00000000000..97df9e70ce7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.telnet.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/build.properties new file mode 100644 index 00000000000..c33f2d71b1e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/feature.properties new file mode 100644 index 00000000000..a3b734b888f --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Telnet Connector Extensions + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A Telnet connector implementation for the Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2003, 2017 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/feature.xml new file mode 100644 index 00000000000..9d3b67a4c24 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/feature.xml @@ -0,0 +1,51 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/pom.xml new file mode 100644 index 00000000000..49038af80cc --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.telnet.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/.project new file mode 100644 index 00000000000..7abe52415a8 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.connector.telnet.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/build.properties new file mode 100644 index 00000000000..c33f2d71b1e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/feature.properties new file mode 100644 index 00000000000..0c4787ac81c --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/feature.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Telnet Connector Extensions, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=A Telnet connector implementation for the Terminal. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2003, 2017 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/feature.xml new file mode 100644 index 00000000000..2792c30cafd --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/feature.xml @@ -0,0 +1,50 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/pom.xml new file mode 100644 index 00000000000..b7efd30ce3d --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.connector.telnet.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.connector.telnet.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.control.feature/.project b/terminal/features/org.eclipse.tm.terminal.control.feature/.project new file mode 100644 index 00000000000..2002b5a3f20 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.control.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.control.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.control.feature/build.properties new file mode 100644 index 00000000000..bfccdf49079 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.control.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.control.feature/feature.properties new file mode 100644 index 00000000000..df9c50ce7f9 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.feature/feature.properties @@ -0,0 +1,39 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Control + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.4 Updates + +# "description" property - description of the feature +description=An ANSI (vt102) compatible Terminal widget \ +with RCP-only dependencies. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2003, 2018 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.control.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.control.feature/feature.xml new file mode 100644 index 00000000000..f0429f896ea --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.feature/feature.xml @@ -0,0 +1,49 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.control.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.control.feature/pom.xml new file mode 100644 index 00000000000..60580345f14 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.feature/pom.xml @@ -0,0 +1,45 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + 4.5.102-SNAPSHOT + + org.eclipse.tm.terminal.control.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/.project new file mode 100644 index 00000000000..09a6bce3e20 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/.project @@ -0,0 +1,17 @@ + + + org.eclipse.tm.terminal.control.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + diff --git a/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/build.properties new file mode 100644 index 00000000000..bfccdf49079 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/build.properties @@ -0,0 +1,13 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Uwe Stieber (Wind River) - Bug 434937 - Releng: The Terminal Features have an incorrect license +################################################################################ +bin.includes = feature.xml,\ + feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/feature.properties new file mode 100644 index 00000000000..acbfce1de76 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/feature.properties @@ -0,0 +1,39 @@ +############################################################################### +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Martin Oberhuber (Wind River) - initial API and implementation +############################################################################### +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal Control, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.4 Updates + +# "description" property - description of the feature +description=An ANSI (vt102) compatible Terminal widget \ +with RCP-only dependencies. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2003, 2018 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/feature.xml new file mode 100644 index 00000000000..07d5e69347d --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/feature.xml @@ -0,0 +1,47 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/pom.xml new file mode 100644 index 00000000000..0d4df06551b --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.control.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.control.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.feature/.project b/terminal/features/org.eclipse.tm.terminal.feature/.project new file mode 100644 index 00000000000..a456794a2fa --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.feature/.project @@ -0,0 +1,28 @@ + + + org.eclipse.tm.terminal.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + + + 1311579318584 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.feature/build.properties new file mode 100644 index 00000000000..b801dc44f40 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.feature/build.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +bin.includes = feature.xml,\ + feature.properties,\ + p2.inf +src.includes = feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.feature/feature.properties new file mode 100644 index 00000000000..bd474c35387 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.feature/feature.properties @@ -0,0 +1,40 @@ +################################################################################## +# Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.4 Updates + +# "description" property - description of the feature +description=An integrated Eclipse View for the local command prompt (console) or \ + remote hosts (SSH, Telnet, Serial). Works on Windows, Linux, Mac and Solaris. \ + Requires Eclipse 3.8.2 or newer and a Java 6 or newer JRE. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2011 - 2018 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ + +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.feature/feature.xml new file mode 100644 index 00000000000..2c69251458e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.feature/feature.xml @@ -0,0 +1,40 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.feature/p2.inf b/terminal/features/org.eclipse.tm.terminal.feature/p2.inf new file mode 100644 index 00000000000..a6c5ff197fb --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.feature/p2.inf @@ -0,0 +1,5 @@ +update.id=org.eclipse.tcf.te.terminals.feature.feature.group +update.range=(0,$version$) +provides.99.namespace=org.eclipse.equinox.p2.iu +provides.99.name=org.eclipse.tcf.te.terminals.feature.feature.group +provides.99.version=$version$ diff --git a/terminal/features/org.eclipse.tm.terminal.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.feature/pom.xml new file mode 100644 index 00000000000..7794403d6bc --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.feature/pom.xml @@ -0,0 +1,45 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.feature + 4.5.200-SNAPSHOT + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.sdk.feature/.project new file mode 100644 index 00000000000..48e5c337375 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.sdk.feature/.project @@ -0,0 +1,33 @@ + + + org.eclipse.tm.terminal.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.FeatureNature + + + + 1311579318584 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.sdk.feature/build.properties new file mode 100644 index 00000000000..9ac7f804cc8 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.sdk.feature/build.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +bin.includes = feature.xml,\ + feature.properties +src.includes = feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.sdk.feature/feature.properties new file mode 100644 index 00000000000..3f78a9b8022 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.sdk.feature/feature.properties @@ -0,0 +1,40 @@ +################################################################################## +# Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=TM Terminal, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.4 Updates + +# "description" property - description of the feature +description=An integrated Eclipse View for the local command prompt (console) or \ + remote hosts via (SSH, Telnet, Serial). Works on Windows, Linux, Mac and Solaris. \ + Requires Eclipse 3.8.2 or newer and a Java 6 or newer JRE. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2011 - 2018 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ + +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.sdk.feature/feature.xml new file mode 100644 index 00000000000..ca554a3bd9b --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.sdk.feature/feature.xml @@ -0,0 +1,44 @@ + + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.sdk.feature/p2.inf b/terminal/features/org.eclipse.tm.terminal.sdk.feature/p2.inf new file mode 100644 index 00000000000..d5add3dbcc3 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.sdk.feature/p2.inf @@ -0,0 +1,5 @@ +update.id=org.eclipse.tcf.te.terminals.sdk.feature.feature.group +update.range=(0,$version$) +provides.99.namespace=org.eclipse.equinox.p2.iu +provides.99.name=org.eclipse.tcf.te.terminals.sdk.feature.feature.group +provides.99.version=$version$ diff --git a/terminal/features/org.eclipse.tm.terminal.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.sdk.feature/pom.xml new file mode 100644 index 00000000000..e5168cc7f29 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.view.feature/.project b/terminal/features/org.eclipse.tm.terminal.view.feature/.project new file mode 100644 index 00000000000..1320e7a6255 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.feature/.project @@ -0,0 +1,28 @@ + + + org.eclipse.tm.terminal.view.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + + org.eclipse.pde.FeatureNature + + + + 1311579318584 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.view.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.view.feature/build.properties new file mode 100644 index 00000000000..b801dc44f40 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.feature/build.properties @@ -0,0 +1,15 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +bin.includes = feature.xml,\ + feature.properties,\ + p2.inf +src.includes = feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.view.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.view.feature/feature.properties new file mode 100644 index 00000000000..11b4c39a1f7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.feature/feature.properties @@ -0,0 +1,40 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=Terminal (Console) View + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=An integrated Eclipse View for the local command prompt (console) or \ + remote hosts (SSH, Telnet, Serial). Works on Windows, Linux, Mac and Solaris. \ + Requires Eclipse 3.8.2 or newer and a Java 6 or newer JRE. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2011 - 2016 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ + +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.view.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.view.feature/feature.xml new file mode 100644 index 00000000000..2c4ec8b696b --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.feature/feature.xml @@ -0,0 +1,54 @@ + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.view.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.view.feature/pom.xml new file mode 100644 index 00000000000..4188445839a --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.feature/pom.xml @@ -0,0 +1,45 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.view.feature + 4.5.200-SNAPSHOT + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/.project b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/.project new file mode 100644 index 00000000000..c8ba6fd3f78 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/.project @@ -0,0 +1,33 @@ + + + org.eclipse.tm.terminal.view.sdk.feature + + + + + + org.eclipse.pde.FeatureBuilder + + + + + org.eclipse.pde.ds.core.builder + + + + + + org.eclipse.pde.FeatureNature + + + + 1311579318584 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/build.properties b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/build.properties new file mode 100644 index 00000000000..9ac7f804cc8 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/build.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +bin.includes = feature.xml,\ + feature.properties +src.includes = feature.properties diff --git a/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/feature.properties b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/feature.properties new file mode 100644 index 00000000000..ce319c28598 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/feature.properties @@ -0,0 +1,40 @@ +################################################################################## +# Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## +# feature.properties +# contains externalized strings for feature.xml +# "%foo" in feature.xml corresponds to the key "foo" in this file +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file should be translated. + +# "featureName" property - name of the feature +featureName=Terminal (Console) View, SDK + +# "providerName" property - name of the company that provides the feature +providerName=Eclipse.org - Target Management + +# "updateSiteName" property - label for the update site +updateSiteName=TM Terminal 4.3 Updates + +# "description" property - description of the feature +description=An integrated Eclipse View for the local command prompt (console) or \ + remote hosts via (SSH, Telnet, Serial). Works on Windows, Linux, Mac and Solaris. \ + Requires Eclipse 3.8.2 or newer and a Java 6 or newer JRE. + +# "copyright" property - text of the "Feature Update Copyright" +copyright=\ +Copyright (c) 2011 - 2016 Wind River Systems, Inc. and others.\n\ +All rights reserved. This program and the accompanying materials\n\ +are made available under the terms of the Eclipse Public License 2.0\n\ +which accompanies this distribution, and is available at\n\ +https://www.eclipse.org/legal/epl-2.0/ + +################ end of copyright property #################################### diff --git a/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/feature.xml b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/feature.xml new file mode 100644 index 00000000000..9ef7dab4d7e --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/feature.xml @@ -0,0 +1,50 @@ + + + + + + + %description + + + + %copyright + + + + %license + + + + + + + + + diff --git a/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/pom.xml b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/pom.xml new file mode 100644 index 00000000000..74c6faf6ae7 --- /dev/null +++ b/terminal/features/org.eclipse.tm.terminal.view.sdk.feature/pom.xml @@ -0,0 +1,44 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.features + 4.5.100-SNAPSHOT + + + org.eclipse.tm.terminal.view.sdk.feature + eclipse-feature + + + true + + + + + + + org.eclipse.tycho + tycho-packaging-plugin + ${tycho-version} + + default + + + + + + diff --git a/terminal/features/pom.xml b/terminal/features/pom.xml new file mode 100644 index 00000000000..1da93e88e52 --- /dev/null +++ b/terminal/features/pom.xml @@ -0,0 +1,69 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../admin/pom-build.xml + + + org.eclipse.tm.terminal.features + + pom + + + org.eclipse.tm.terminal.control.feature + org.eclipse.tm.terminal.control.sdk.feature + + org.eclipse.tm.terminal.connector.local.feature + org.eclipse.tm.terminal.connector.local.sdk.feature + org.eclipse.tm.terminal.connector.remote.feature + org.eclipse.tm.terminal.connector.remote.sdk.feature + org.eclipse.tm.terminal.connector.ssh.feature + org.eclipse.tm.terminal.connector.ssh.sdk.feature + org.eclipse.tm.terminal.connector.telnet.feature + org.eclipse.tm.terminal.connector.telnet.sdk.feature + + org.eclipse.tm.terminal.view.feature + org.eclipse.tm.terminal.view.sdk.feature + + org.eclipse.tm.terminal.feature + org.eclipse.tm.terminal.sdk.feature + + + + + + + cdtserial + + + + true + + !nocdtserial + + + + org.eclipse.tm.terminal.connector.cdtserial.feature + org.eclipse.tm.terminal.connector.cdtserial.sdk.feature + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.classpath b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.classpath new file mode 100644 index 00000000000..eca7bdba8f0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.options b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.options new file mode 100644 index 00000000000..7a6120d0244 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.options @@ -0,0 +1,2 @@ +org.eclipse.tm.terminal.connector.serial/debugmode = 0 +org.eclipse.tm.terminal.connector.serial/trace/serialLinePanel = false diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.project b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.project new file mode 100644 index 00000000000..4a564b77c17 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.project @@ -0,0 +1,34 @@ + + + org.eclipse.tm.terminal.connector.cdtserial + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..6f5171a972b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,361 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.8 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..e131cd1b6f4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/META-INF/MANIFEST.MF @@ -0,0 +1,23 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.connector.cdtserial;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Activator: org.eclipse.tm.terminal.connector.cdtserial.activator.Activator +Bundle-Vendor: %providerName +Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.equinox.security;bundle-version="1.1.100", + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.view.ui;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.ui;bundle-version="3.8.0", + org.eclipse.cdt.native.serial;bundle-version="1.0.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.connector.cdtserial.activator;x-internal:=true, + org.eclipse.tm.terminal.connector.cdtserial.connector, + org.eclipse.tm.terminal.connector.cdtserial.controls, + org.eclipse.tm.terminal.connector.cdtserial.launcher, + org.eclipse.tm.terminal.connector.cdtserial.nls;x-internal:=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/about.html b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

May 24, 2012

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/build.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/build.properties new file mode 100644 index 00000000000..1c3465df7d0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/build.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + plugin.xml,\ + about.html diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/plugin.properties new file mode 100644 index 00000000000..b7e4a56d546 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/plugin.properties @@ -0,0 +1,22 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal Serial Connector +providerName = Eclipse.org - Target Management + +# ----- Terminal Launcher Delegates ----- + +SerialLauncherDelegate.label=Serial Terminal + +# ----- Terminal Connectors ----- + +SerialConnector.label = Serial diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/plugin.xml new file mode 100644 index 00000000000..583c143166c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/plugin.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/pom.xml new file mode 100644 index 00000000000..2c35890725e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.connector.cdtserial + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/activator/Activator.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/activator/Activator.java new file mode 100644 index 00000000000..84edbb2733a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/activator/Activator.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.activator; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tm.terminal.view.core.tracing.TraceHandler; +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 shared instance + private static Activator plugin; + // The trace handler instance + private static volatile TraceHandler traceHandler; + + /** + * The constructor + */ + public Activator() { + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static Activator getDefault() { + return plugin; + } + + /** + * Convenience method which returns the unique identifier of this plugin. + */ + public static String getUniqueIdentifier() { + if (getDefault() != null && getDefault().getBundle() != null) { + return getDefault().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.connector.serial"; //$NON-NLS-1$ + } + + /** + * Returns the bundles trace handler. + * + * @return The bundles trace handler. + */ + public static TraceHandler getTraceHandler() { + if (traceHandler == null) { + traceHandler = new TraceHandler(getUniqueIdentifier()); + } + return traceHandler; + } + + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + @Override + protected void initializeImageRegistry(ImageRegistry registry) { + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the Image object instance. + * + * @param key The key the image is registered with. + * @return The Image object instance or null. + */ + public static Image getImage(String key) { + return getDefault().getImageRegistry().get(key); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the ImageDescriptor object instance. + * + * @param key The key the image is registered with. + * @return The ImageDescriptor object instance or null. + */ + public static ImageDescriptor getImageDescriptor(String key) { + return getDefault().getImageRegistry().getDescriptor(key); + } + + public static void log(IStatus status) { + plugin.getLog().log(status); + } + + public static void log(Exception exception) { + if (exception instanceof CoreException) { + log(((CoreException) exception).getStatus()); + } else { + log(new Status(IStatus.ERROR, plugin.getBundle().getSymbolicName(), exception.getLocalizedMessage(), exception)); + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/connector/SerialConnector.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/connector/SerialConnector.java new file mode 100644 index 00000000000..9cfa234910b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/connector/SerialConnector.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.connector; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.HashSet; +import java.util.Set; + +import org.eclipse.cdt.serial.SerialPort; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; +import org.eclipse.tm.terminal.connector.cdtserial.activator.Activator; + +public class SerialConnector extends TerminalConnectorImpl { + + private SerialSettings settings = new SerialSettings(); + SerialPort serialPort; + + private static Set openPorts = new HashSet<>(); + + public static boolean isOpen(String portName) { + return openPorts.contains(portName); + } + + @Override + public OutputStream getTerminalToRemoteStream() { + return serialPort.getOutputStream(); + } + + public SerialSettings getSettings() { + return settings; + } + + public SerialPort getSerialPort() { + return serialPort; + } + + @Override + public String getSettingsSummary() { + return settings.getSummary(); + } + + @Override + public void load(ISettingsStore store) { + settings.load(store); + } + + @Override + public void save(ISettingsStore store) { + settings.save(store); + } + + @Override + public void connect(ITerminalControl control) { + super.connect(control); + control.setState(TerminalState.CONNECTING); + + serialPort = new SerialPort(settings.getPortName()); + try { + serialPort.setBaudRate(settings.getBaudRate()); + serialPort.setByteSize(settings.getByteSize()); + serialPort.setParity(settings.getParity()); + serialPort.setStopBits(settings.getStopBits()); + serialPort.open(); + } catch (IOException e) { + Activator.log(e); + control.setState(TerminalState.CLOSED); + return; + } + + openPorts.add(serialPort.getPortName()); + + new Thread() { + @Override + public void run() { + InputStream targetIn = serialPort.getInputStream(); + byte[] buff = new byte[256]; + int n; + try { + while ((n = targetIn.read(buff, 0, buff.length)) >= 0) { + if (n != 0) { + control.getRemoteToTerminalOutputStream().write(buff, 0, n); + } + } + disconnect(); + } catch (IOException e) { + Activator.log(e); + } + } + }.start(); + control.setState(TerminalState.CONNECTED); + } + + @Override + protected void doDisconnect() { + if (serialPort != null && serialPort.isOpen()) { + openPorts.remove(serialPort.getPortName()); + try { + serialPort.close(); + } catch (IOException e) { + Activator.log(e); + } + } + serialPort = null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/connector/SerialSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/connector/SerialSettings.java new file mode 100644 index 00000000000..444acb6b5ce --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/connector/SerialSettings.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.connector; + +import org.eclipse.cdt.serial.BaudRate; +import org.eclipse.cdt.serial.ByteSize; +import org.eclipse.cdt.serial.Parity; +import org.eclipse.cdt.serial.StopBits; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +public class SerialSettings { + + public static final String PORT_NAME_ATTR = "cdtserial.portName"; //$NON-NLS-1$ + public static final String BAUD_RATE_ATTR = "cdtserial.baudRate"; //$NON-NLS-1$ + public static final String BYTE_SIZE_ATTR = "cdtserial.byteSize"; //$NON-NLS-1$ + public static final String PARITY_ATTR = "cdtserial.parity"; //$NON-NLS-1$ + public static final String STOP_BITS_ATTR = "cdtserial.stopBits"; //$NON-NLS-1$ + + private String portName; + private BaudRate baudRate; + private ByteSize byteSize; + private Parity parity; + private StopBits stopBits; + + /** + * Load information into the RemoteSettings object. + */ + public void load(ISettingsStore store) { + portName = store.get(PORT_NAME_ATTR, ""); //$NON-NLS-1$ + + String baudRateStr = store.get(BAUD_RATE_ATTR, ""); //$NON-NLS-1$ + if (baudRateStr.isEmpty()) { + baudRate = BaudRate.getDefault(); + } else { + String[] rates = BaudRate.getStrings(); + for (int i = 0; i < rates.length; ++i) { + if (baudRateStr.equals(rates[i])) { + baudRate = BaudRate.fromStringIndex(i); + break; + } + } + } + + String byteSizeStr = store.get(BYTE_SIZE_ATTR, ""); //$NON-NLS-1$ + if (byteSizeStr.isEmpty()) { + byteSize = ByteSize.getDefault(); + } else { + String[] sizes = ByteSize.getStrings(); + for (int i = 0; i < sizes.length; ++i) { + if (byteSizeStr.equals(sizes[i])) { + byteSize = ByteSize.fromStringIndex(i); + break; + } + } + } + + String parityStr = store.get(PARITY_ATTR, ""); //$NON-NLS-1$ + if (parityStr.isEmpty()) { + parity = Parity.getDefault(); + } else { + String[] parities = Parity.getStrings(); + for (int i = 0; i < parities.length; ++i) { + if (parityStr.equals(parities[i])) { + parity = Parity.fromStringIndex(i); + break; + } + } + } + + String stopBitsStr = store.get(STOP_BITS_ATTR, ""); //$NON-NLS-1$ + if (stopBitsStr.isEmpty()) { + stopBits = StopBits.getDefault(); + } else { + String[] bits = StopBits.getStrings(); + for (int i = 0; i < bits.length; ++i) { + if (stopBitsStr.equals(bits[i])) { + stopBits = StopBits.fromStringIndex(i); + break; + } + } + } + } + + /** + * Extract information from the RemoteSettings object. + */ + public void save(ISettingsStore store) { + store.put(PORT_NAME_ATTR, portName); + store.put(BAUD_RATE_ATTR, BaudRate.getStrings()[BaudRate.getStringIndex(baudRate)]); + store.put(BYTE_SIZE_ATTR, ByteSize.getStrings()[ByteSize.getStringIndex(byteSize)]); + store.put(PARITY_ATTR, Parity.getStrings()[Parity.getStringIndex(parity)]); + store.put(STOP_BITS_ATTR, StopBits.getStrings()[StopBits.getStringIndex(stopBits)]); + } + + public String getPortName() { + return portName; + } + + public void setPortName(String portName) { + this.portName = portName; + } + + public BaudRate getBaudRate() { + return baudRate; + } + + public void setBaudRate(BaudRate baudRate) { + this.baudRate = baudRate; + } + + public ByteSize getByteSize() { + return byteSize; + } + + public void setByteSize(ByteSize byteSize) { + this.byteSize = byteSize; + } + + public Parity getParity() { + return parity; + } + + public void setParity(Parity parity) { + this.parity = parity; + } + + public StopBits getStopBits() { + return stopBits; + } + + public void setStopBits(StopBits stopBits) { + this.stopBits = stopBits; + } + + public String getSummary() { + return portName; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/controls/SerialConfigPanel.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/controls/SerialConfigPanel.java new file mode 100644 index 00000000000..fe42b841b52 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/controls/SerialConfigPanel.java @@ -0,0 +1,110 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.controls; + +import java.util.Map; + +import org.eclipse.cdt.serial.BaudRate; +import org.eclipse.cdt.serial.ByteSize; +import org.eclipse.cdt.serial.Parity; +import org.eclipse.cdt.serial.StopBits; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.terminal.connector.cdtserial.connector.SerialConnector; +import org.eclipse.tm.terminal.connector.cdtserial.connector.SerialSettings; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; + +public class SerialConfigPanel extends AbstractExtendedConfigurationPanel { + + private SerialSettings settings; + private SerialSettingsPage page; + + public SerialConfigPanel(IConfigurationPanelContainer container) { + super(container); + } + + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + panel.setLayoutData(data); + + SerialConnector connector = new SerialConnector(); + settings = connector.getSettings(); + page = new SerialSettingsPage(settings, this); + page.createControl(panel); + + createEncodingUI(panel, true); + + setControl(panel); + } + + @Override + public void extractData(Map data) { + if (data == null) { + return; + } + + page.saveSettings(); + data.put(SerialSettings.PORT_NAME_ATTR, settings.getPortName()); + data.put(SerialSettings.BAUD_RATE_ATTR, settings.getBaudRate()); + data.put(SerialSettings.BYTE_SIZE_ATTR, settings.getByteSize()); + data.put(SerialSettings.PARITY_ATTR, settings.getParity()); + data.put(SerialSettings.STOP_BITS_ATTR, settings.getStopBits()); + + if (getEncoding() != null) { + data.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + } + } + + @Override + public void setupData(Map data) { + if (data == null) { + return; + } + + settings.setPortName((String) data.get(SerialSettings.PORT_NAME_ATTR)); + settings.setBaudRate((BaudRate) data.get(SerialSettings.BAUD_RATE_ATTR)); + settings.setByteSize((ByteSize) data.get(SerialSettings.BYTE_SIZE_ATTR)); + settings.setParity((Parity) data.get(SerialSettings.PARITY_ATTR)); + settings.setStopBits((StopBits) data.get(SerialSettings.STOP_BITS_ATTR)); + + String encoding = (String) data.get(ITerminalsConnectorConstants.PROP_ENCODING); + if (encoding != null) { + setEncoding(encoding); + } + } + + @Override + protected void saveSettingsForHost(boolean add) { + } + + @Override + protected void fillSettingsForHost(String host) { + } + + @Override + protected String getHostFromSettings() { + if (page != null) { + page.saveSettings(); + return settings.getPortName(); + } + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/controls/SerialSettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/controls/SerialSettingsPage.java new file mode 100644 index 00000000000..1f9f4f2e151 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/controls/SerialSettingsPage.java @@ -0,0 +1,266 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.controls; + +import java.io.IOException; + +import org.eclipse.cdt.serial.BaudRate; +import org.eclipse.cdt.serial.ByteSize; +import org.eclipse.cdt.serial.Parity; +import org.eclipse.cdt.serial.SerialPort; +import org.eclipse.cdt.serial.StopBits; +import org.eclipse.jface.dialogs.DialogSettings; +import org.eclipse.jface.dialogs.IDialogSettings; +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.Label; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; +import org.eclipse.tm.terminal.connector.cdtserial.activator.Activator; +import org.eclipse.tm.terminal.connector.cdtserial.connector.SerialConnector; +import org.eclipse.tm.terminal.connector.cdtserial.connector.SerialSettings; +import org.eclipse.tm.terminal.connector.cdtserial.nls.Messages; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; + +public class SerialSettingsPage extends AbstractSettingsPage { + + private final SerialSettings settings; + private final IConfigurationPanel panel; + private final IDialogSettings dialogSettings; + + private Combo portCombo; + private Combo baudRateCombo; + private Combo byteSizeCombo; + private Combo parityCombo; + private Combo stopBitsCombo; + + private String portName; + private BaudRate baudRate; + private ByteSize byteSize; + private Parity parity; + private StopBits stopBits; + + public SerialSettingsPage(SerialSettings settings, IConfigurationPanel panel) { + this.settings = settings; + this.panel = panel; + setHasControlDecoration(true); + + dialogSettings = DialogSettings.getOrCreateSection(Activator.getDefault().getDialogSettings(), + this.getClass().getSimpleName()); + portName = dialogSettings.get(SerialSettings.PORT_NAME_ATTR); + + String baudRateStr = dialogSettings.get(SerialSettings.BAUD_RATE_ATTR); + if (baudRateStr == null || baudRateStr.isEmpty()) { + baudRate = BaudRate.getDefault(); + } else { + String[] rates = BaudRate.getStrings(); + for (int i = 0; i < rates.length; ++i) { + if (baudRateStr.equals(rates[i])) { + baudRate = BaudRate.fromStringIndex(i); + break; + } + } + } + + String byteSizeStr = dialogSettings.get(SerialSettings.BYTE_SIZE_ATTR); + if (byteSizeStr == null || byteSizeStr.isEmpty()) { + byteSize = ByteSize.getDefault(); + } else { + String[] sizes = ByteSize.getStrings(); + for (int i = 0; i < sizes.length; ++i) { + if (byteSizeStr.equals(sizes[i])) { + byteSize = ByteSize.fromStringIndex(i); + break; + } + } + } + + String parityStr = dialogSettings.get(SerialSettings.PARITY_ATTR); + if (parityStr == null || parityStr.isEmpty()) { + parity = Parity.getDefault(); + } else { + String[] parities = Parity.getStrings(); + for (int i = 0; i < parities.length; ++i) { + if (parityStr.equals(parities[i])) { + parity = Parity.fromStringIndex(i); + break; + } + } + } + + String stopBitsStr = dialogSettings.get(SerialSettings.STOP_BITS_ATTR); + if (stopBitsStr == null || stopBitsStr.isEmpty()) { + stopBits = StopBits.getDefault(); + } else { + String[] bits = StopBits.getStrings(); + for (int i = 0; i < bits.length; ++i) { + if (stopBitsStr.equals(bits[i])) { + stopBits = StopBits.fromStringIndex(i); + break; + } + } + } + } + + @Override + public void createControl(Composite parent) { + Composite comp = new Composite(parent, SWT.NONE); + GridLayout gridLayout = new GridLayout(2, false); + gridLayout.marginWidth = gridLayout.marginHeight = 0; + GridData gridData = new GridData(GridData.FILL_HORIZONTAL); + comp.setLayout(gridLayout); + comp.setLayoutData(gridData); + + Label portLabel = new Label(comp, SWT.NONE); + portLabel.setText(Messages.SerialTerminalSettingsPage_SerialPort); + + portCombo = new Combo(comp, SWT.NONE); + portCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + String[] portNames = new String[0]; + try { + portNames = SerialPort.list(); + } catch (IOException e) { + Activator.log(e); + } + for (String portName : portNames) { + if (!SerialConnector.isOpen(portName)) { + portCombo.add(portName); + } + } + portCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + validate(); + } + }); + + Label baudRateLabel = new Label(comp, SWT.NONE); + baudRateLabel.setText(Messages.SerialTerminalSettingsPage_BaudRate); + + baudRateCombo = new Combo(comp, SWT.READ_ONLY); + baudRateCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + for (String baudRateStr : BaudRate.getStrings()) { + baudRateCombo.add(baudRateStr); + } + + Label byteSizeLabel = new Label(comp, SWT.NONE); + byteSizeLabel.setText(Messages.SerialTerminalSettingsPage_DataSize); + + byteSizeCombo = new Combo(comp, SWT.READ_ONLY); + byteSizeCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + for (String byteSizeStr : ByteSize.getStrings()) { + byteSizeCombo.add(byteSizeStr); + } + + Label parityLabel = new Label(comp, SWT.NONE); + parityLabel.setText(Messages.SerialTerminalSettingsPage_Parity); + + parityCombo = new Combo(comp, SWT.READ_ONLY); + parityCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + for (String parityStr : Parity.getStrings()) { + parityCombo.add(parityStr); + } + + Label stopBitsLabel = new Label(comp, SWT.NONE); + stopBitsLabel.setText(Messages.SerialTerminalSettingsPage_StopBits); + + stopBitsCombo = new Combo(comp, SWT.READ_ONLY); + stopBitsCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + for (String stopBitsStr : StopBits.getStrings()) { + stopBitsCombo.add(stopBitsStr); + } + + loadSettings(); + } + + void validate() { + IConfigurationPanelContainer container = panel.getContainer(); + container.validate(); + } + + @Override + public void loadSettings() { + String portName = settings.getPortName(); + if (portName == null || portName.isEmpty()) { + portName = this.portName; + } + if (portName != null && !portName.isEmpty() && !SerialConnector.isOpen(portName)) { + int i = 0; + for (String name : portCombo.getItems()) { + if (portName.equals(name)) { + portCombo.select(i); + break; + } + i++; + } + } else if (portCombo.getItemCount() > 0) { + portCombo.select(0); + } + + BaudRate baudRate = settings.getBaudRate(); + if (baudRate == null) { + baudRate = this.baudRate; + } + baudRateCombo.select(BaudRate.getStringIndex(baudRate)); + + ByteSize byteSize = settings.getByteSize(); + if (byteSize == null) { + byteSize = this.byteSize; + } + byteSizeCombo.select(ByteSize.getStringIndex(byteSize)); + + Parity parity = settings.getParity(); + if (parity == null) { + parity = this.parity; + } + parityCombo.select(Parity.getStringIndex(parity)); + + StopBits stopBits = settings.getStopBits(); + if (stopBits == null) { + stopBits = this.stopBits; + } + stopBitsCombo.select(StopBits.getStringIndex(stopBits)); + } + + @Override + public void saveSettings() { + settings.setPortName(portCombo.getText()); + settings.setBaudRate(BaudRate.fromStringIndex(baudRateCombo.getSelectionIndex())); + settings.setByteSize(ByteSize.fromStringIndex(byteSizeCombo.getSelectionIndex())); + settings.setParity(Parity.fromStringIndex(parityCombo.getSelectionIndex())); + settings.setStopBits(StopBits.fromStringIndex(stopBitsCombo.getSelectionIndex())); + + dialogSettings.put(SerialSettings.PORT_NAME_ATTR, portCombo.getText()); + dialogSettings.put(SerialSettings.BAUD_RATE_ATTR, + BaudRate.getStrings()[baudRateCombo.getSelectionIndex()]); + dialogSettings.put(SerialSettings.BYTE_SIZE_ATTR, + ByteSize.getStrings()[byteSizeCombo.getSelectionIndex()]); + dialogSettings.put(SerialSettings.PARITY_ATTR, Parity.getStrings()[parityCombo.getSelectionIndex()]); + dialogSettings.put(SerialSettings.STOP_BITS_ATTR, + StopBits.getStrings()[stopBitsCombo.getSelectionIndex()]); + } + + @Override + public boolean validateSettings() { + if (portCombo.getSelectionIndex() < 0 && portCombo.getText().isEmpty()) { + return false; + } + return true; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/launcher/SerialLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/launcher/SerialLauncherDelegate.java new file mode 100644 index 00000000000..05b49a0aa27 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/launcher/SerialLauncherDelegate.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.launcher; + +import java.util.Map; + +import org.eclipse.cdt.serial.BaudRate; +import org.eclipse.cdt.serial.ByteSize; +import org.eclipse.cdt.serial.Parity; +import org.eclipse.cdt.serial.StopBits; +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.connector.cdtserial.connector.SerialSettings; +import org.eclipse.tm.terminal.connector.cdtserial.controls.SerialConfigPanel; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +public class SerialLauncherDelegate extends AbstractLauncherDelegate { + + @Override + public boolean needsUserConfiguration() { + return true; + } + + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return new SerialConfigPanel(container); + } + + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String) properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) { + connectorId = "org.eclipse.tm.terminal.connector.cdtserial.SerialConnector"; //$NON-NLS-1$ + } + + // Extract the properties + SerialSettings settings = new SerialSettings(); + settings.setPortName((String) properties.get(SerialSettings.PORT_NAME_ATTR)); + settings.setBaudRate((BaudRate) properties.get(SerialSettings.BAUD_RATE_ATTR)); + settings.setByteSize((ByteSize) properties.get(SerialSettings.BYTE_SIZE_ATTR)); + settings.setParity((Parity) properties.get(SerialSettings.PARITY_ATTR)); + settings.setStopBits((StopBits) properties.get(SerialSettings.STOP_BITS_ATTR)); + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + settings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + return connector; + } + + @Override + public void execute(Map properties, Done done) { + Assert.isNotNull(properties); + + // Set the terminal tab title + String name = (String) properties.get(SerialSettings.PORT_NAME_ATTR); + properties.put(ITerminalsConnectorConstants.PROP_TITLE, name); + + // Force a new terminal tab each time it is launched, if not set otherwise from outside + // TODO need a command shell service routing to get this + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_FORCE_NEW)) { + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, Boolean.TRUE); + } + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/nls/Messages.java new file mode 100644 index 00000000000..a43aaaafc0e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/nls/Messages.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2017, 2018 QNX Software Systems and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * QNX Software Systems - Initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.cdtserial.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.connector.cdtserial.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String SerialTerminalSettingsPage_BaudRate; + public static String SerialTerminalSettingsPage_DataSize; + public static String SerialTerminalSettingsPage_Parity; + public static String SerialTerminalSettingsPage_SerialPort; + public static String SerialTerminalSettingsPage_StopBits; + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/nls/Messages.properties new file mode 100644 index 00000000000..9052b4e2c66 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.cdtserial/src/org/eclipse/tm/terminal/connector/cdtserial/nls/Messages.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2017, 2018 QNX Software Systems and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# QNX Software Systems - Initial API and implementation +############################################################################### + +SerialTerminalSettingsPage_BaudRate=Baud rate: +SerialTerminalSettingsPage_DataSize=Data size: +SerialTerminalSettingsPage_Parity=Parity: +SerialTerminalSettingsPage_SerialPort=Serial port: +SerialTerminalSettingsPage_StopBits=Stop bits: diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.classpath b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.options b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.options new file mode 100644 index 00000000000..5cbcb6722b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.options @@ -0,0 +1 @@ +org.eclipse.tm.terminal.connector.local/debugmode = 0 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.project b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.project new file mode 100644 index 00000000000..696a343153f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.project @@ -0,0 +1,45 @@ + + + org.eclipse.tm.terminal.connector.local + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + + + 0 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..24dad4464e4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,362 @@ +#Tue Oct 11 11:53:38 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.connector.local/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..4bc3ca52378 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.connector.local;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Activator: org.eclipse.tm.terminal.connector.local.activator.UIPlugin +Bundle-Vendor: %providerName +Import-Package: org.eclipse.cdt.utils.pty;mandatory:=native +Require-Bundle: org.eclipse.cdt.core;bundle-version="5.6.0";resolution:=optional, + org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.resources;bundle-version="3.8.1";resolution:=optional, + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.core.variables;bundle-version="3.2.600", + org.eclipse.debug.ui;bundle-version="3.8.1";resolution:=optional, + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.view.ui;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.connector.process;bundle-version="4.5.0", + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.ui;bundle-version="3.8.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.connector.local.activator;x-internal:=true, + org.eclipse.tm.terminal.connector.local.controls, + org.eclipse.tm.terminal.connector.local.launcher diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/META-INF/p2.inf b/terminal/plugins/org.eclipse.tm.terminal.connector.local/META-INF/p2.inf new file mode 100644 index 00000000000..3aec0927ef9 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/META-INF/p2.inf @@ -0,0 +1,82 @@ +############################################################################### +# Copyright (c) 2014 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +# Most of the dependencies exposed here are actually covered in the feature.xml +# This file ensures that the current bundle has all it needs, even if installed +# without the enclosing org.eclipse.tcf.te.terminals.feature . +# See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=435150 . + +# 1. Make the optional cdt.core dependency non-greedy: Use (or update to proper +# version!) when installed, but do not install automatically since the newer +# org.eclipse.cdt.core.native can satisfy the dependency better. We use this +# trick since CDT 8.3 had no version on export-package yet but we do want +# a version constraint. +requires.0.namespace = org.eclipse.equinox.p2.iu +requires.0.name = org.eclipse.cdt.core +#requires.0.range = [5.6, 6.0) +requires.0.greedy = false +requires.0.optional = true + +#requires.1.namespace = org.eclipse.equinox.p2.iu +#requires.1.name = org.eclipse.cdt.core.native +#requires.1.range = [5.6, 6.0) +#requires.1.greedy = true +#requires.1.optional = true + +# 2. Add the required fragments for local terminal support with proper version. +requires.2.namespace = org.eclipse.equinox.p2.iu +requires.2.name = org.eclipse.cdt.core.aix +#requires.2.range = [5.3, 6.0) +requires.2.filter = (osgi.os=aix) + +requires.3.namespace = org.eclipse.equinox.p2.iu +requires.3.name = org.eclipse.cdt.core.linux +#requires.3.range = [5.2, 6.0) +requires.3.filter = (osgi.os=linux) + +requires.4.namespace = org.eclipse.equinox.p2.iu +requires.4.name = org.eclipse.cdt.core.linux.ppc64 +#requires.4.range = [5.1, 6.0) +requires.4.filter = (&(osgi.os=linux)(osgi.arch=ppc64)) + +#requires.5.namespace = org.eclipse.equinox.p2.iu +#requires.5.name = org.eclipse.cdt.core.linux.x86 +#requires.5.range = [5.2, 6.0) +#requires.5.filter = (&(osgi.os=linux)(osgi.arch=x86)) + +requires.6.namespace = org.eclipse.equinox.p2.iu +requires.6.name = org.eclipse.cdt.core.linux.x86_64 +#requires.6.range = [5.2, 6.0) +requires.6.filter = (&(osgi.os=linux)(osgi.arch=x86_64)) + +requires.7.namespace = org.eclipse.equinox.p2.iu +requires.7.name = org.eclipse.cdt.core.macosx +#requires.7.range = [5.2, 6.0) +requires.7.filter = (osgi.os=macosx) + +requires.8.namespace = org.eclipse.equinox.p2.iu +requires.8.name = org.eclipse.cdt.core.solaris +#requires.8.range = [5.2, 6.0) +requires.8.filter = (&(osgi.os=solaris)(osgi.arch=sparc)) + +requires.9.namespace = org.eclipse.equinox.p2.iu +requires.9.name = org.eclipse.cdt.core.win32 +#requires.9.range = [5.3, 6.0) +requires.9.filter = (osgi.os=win32) + +#requires.10.namespace = org.eclipse.equinox.p2.iu +#requires.10.name = org.eclipse.cdt.core.win32.x86 +#requires.10.range = [5.2, 6.0) +#requires.10.filter = (&(osgi.os=win32)(osgi.arch=x86)) + +requires.11.namespace = org.eclipse.equinox.p2.iu +requires.11.name = org.eclipse.cdt.core.win32.x86_64 +#requires.11.range = [5.2, 6.0) +requires.11.filter = (&(osgi.os=win32)(osgi.arch=x86_64)) diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/about.html b/terminal/plugins/org.eclipse.tm.terminal.connector.local/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

May 24, 2012

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/build.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.local/build.properties new file mode 100644 index 00000000000..c4d9151b7b7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/build.properties @@ -0,0 +1,19 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html,\ + icons/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/icons/eview16/terminal_view.gif b/terminal/plugins/org.eclipse.tm.terminal.connector.local/icons/eview16/terminal_view.gif new file mode 100644 index 00000000000..bbb6a9e153e Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.connector.local/icons/eview16/terminal_view.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.local/plugin.properties new file mode 100644 index 00000000000..6ce98f79939 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/plugin.properties @@ -0,0 +1,27 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal Local Connector +providerName = Eclipse.org - Target Management + +# ----- Commands and Menu contributions ----- +LocalLauncherDelegate.label=Local Terminal + +command.launch.name=Open Local Terminal on Selection + +menu.showIn.localterminal.label = Terminal + +TerminalConnector.local=Local + +# ----- Preference Pages ----- + +preference.page.name=Local Terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.local/plugin.xml new file mode 100644 index 00000000000..b394dd40b44 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/plugin.xml @@ -0,0 +1,157 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.local/pom.xml new file mode 100644 index 00000000000..88f03dacc85 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.connector.local + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/activator/UIPlugin.java b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/activator/UIPlugin.java new file mode 100644 index 00000000000..c725a5cdbcc --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/activator/UIPlugin.java @@ -0,0 +1,129 @@ +/******************************************************************************* + * Copyright (c) 2012 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.local.activator; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tm.terminal.view.core.preferences.ScopedEclipsePreferences; +import org.eclipse.tm.terminal.view.core.tracing.TraceHandler; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class UIPlugin extends AbstractUIPlugin { + // The shared instance + private static UIPlugin plugin; + // The scoped preferences instance + private static volatile ScopedEclipsePreferences scopedPreferences; + // The trace handler instance + private static volatile TraceHandler traceHandler; + + /** + * The constructor + */ + public UIPlugin() { + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static UIPlugin getDefault() { + return plugin; + } + + /** + * Convenience method which returns the unique identifier of this plug-in. + */ + public static String getUniqueIdentifier() { + if (getDefault() != null && getDefault().getBundle() != null) { + return getDefault().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.connector.local"; //$NON-NLS-1$ + } + + /** + * Return the scoped preferences for this plug-in. + */ + public static ScopedEclipsePreferences getScopedPreferences() { + if (scopedPreferences == null) { + scopedPreferences = new ScopedEclipsePreferences(getUniqueIdentifier()); + } + return scopedPreferences; + } + + /** + * Returns the bundles trace handler. + * + * @return The bundles trace handler. + */ + public static TraceHandler getTraceHandler() { + if (traceHandler == null) { + traceHandler = new TraceHandler(getUniqueIdentifier()); + } + return traceHandler; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + scopedPreferences = null; + traceHandler = null; + super.stop(context); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry) + */ + @Override + protected void initializeImageRegistry(ImageRegistry registry) { + super.initializeImageRegistry(registry); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the Image object instance. + * + * @param key The key the image is registered with. + * @return The Image object instance or null. + */ + public static Image getImage(String key) { + return getDefault().getImageRegistry().get(key); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the ImageDescriptor object instance. + * + * @param key The key the image is registered with. + * @return The ImageDescriptor object instance or null. + */ + public static ImageDescriptor getImageDescriptor(String key) { + return getDefault().getImageRegistry().getDescriptor(key); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/controls/LocalWizardConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/controls/LocalWizardConfigurationPanel.java new file mode 100644 index 00000000000..28f0bcab2cb --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/controls/LocalWizardConfigurationPanel.java @@ -0,0 +1,196 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.local.controls; + +import java.util.Map; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; +import org.eclipse.ui.ISelectionService; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.WorkbenchEncoding; +import org.osgi.framework.Bundle; + +/** + * Serial wizard configuration panel implementation. + */ +public class LocalWizardConfigurationPanel extends AbstractExtendedConfigurationPanel { + + private Object resource; + + /** + * Constructor. + * + * @param container The configuration panel container or null. + */ + public LocalWizardConfigurationPanel(IConfigurationPanelContainer container) { + super(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupPanel(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + // Create the encoding selection combo + createEncodingUI(panel, false); + + // Set the default encoding: + // Default UTF-8 on Mac or Windows for Local, Preferences:Platform encoding otherwise + if (Platform.OS_MACOSX.equals(Platform.getOS()) || Platform.OS_WIN32.equals(Platform.getOS())) { + setEncoding("UTF-8"); //$NON-NLS-1$ + } else { + String encoding = WorkbenchEncoding.getWorkbenchDefaultEncoding(); + if (encoding != null && !"".equals(encoding)) setEncoding(encoding); //$NON-NLS-1$ + } + + // Fill the rest of the panel with a label to be able to + // set a height and width hint for the dialog + Label label = new Label(panel, SWT.HORIZONTAL); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.widthHint = 300; + layoutData.heightHint = 80; + label.setLayoutData(layoutData); + + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + resource = getSelectionResource(); + } + + setControl(panel); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#setupData(java.util.Map) + */ + @Override + public void setupData(Map data) { + if (data == null) return; + + String value = (String)data.get(ITerminalsConnectorConstants.PROP_ENCODING); + if (value != null) setEncoding(value); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#extractData(java.util.Map) + */ + @Override + public void extractData(Map data) { + // set the terminal connector id for local terminal + data.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, "org.eclipse.tm.terminal.connector.local.LocalConnector"); //$NON-NLS-1$ + + // Store the encoding + data.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + // if we have a IResource selection use the location for working directory + if (resource instanceof org.eclipse.core.resources.IResource){ + String dir = ((org.eclipse.core.resources.IResource)resource).getProject().getLocation().toString(); + data.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, dir); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#fillSettingsForHost(java.lang.String) + */ + @Override + protected void fillSettingsForHost(String host){ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#saveSettingsForHost(boolean) + */ + @Override + protected void saveSettingsForHost(boolean add){ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#isValid() + */ + @Override + public boolean isValid(){ + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#doSaveWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + // Save the encodings widget values + doSaveEncodingsWidgetValues(settings, idPrefix); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#doRestoreWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doRestoreWidgetValues(IDialogSettings settings, String idPrefix) { + // Restore the encodings widget values + doRestoreEncodingsWidgetValues(settings, idPrefix); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#getHostFromSettings() + */ + @Override + protected String getHostFromSettings() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#isWithHostList() + */ + @Override + public boolean isWithHostList() { + return false; + } + + /** + * Returns the IResource from the current selection + * + * @return the IResource, or null. + */ + private org.eclipse.core.resources.IResource getSelectionResource() { + ISelectionService selectionService = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); + ISelection selection = selectionService != null ? selectionService.getSelection() : StructuredSelection.EMPTY; + + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + if (element instanceof org.eclipse.core.resources.IResource){ + return ((org.eclipse.core.resources.IResource)element); + } + if (element instanceof IAdaptable) { + return (org.eclipse.core.resources.IResource) ((IAdaptable) element).getAdapter(org.eclipse.core.resources.IResource.class); + } + } + return null; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalLauncherDelegate.java new file mode 100644 index 00000000000..a7277d69dbf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalLauncherDelegate.java @@ -0,0 +1,409 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.local.launcher; + +import java.io.File; +import java.net.InetAddress; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.core.variables.IStringVariableManager; +import org.eclipse.core.variables.VariablesPlugin; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.connector.local.activator.UIPlugin; +import org.eclipse.tm.terminal.connector.local.controls.LocalWizardConfigurationPanel; +import org.eclipse.tm.terminal.connector.process.ProcessSettings; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ILineSeparatorConstants; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.tm.terminal.view.ui.interfaces.IPreferenceKeys; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; +import org.eclipse.ui.ISelectionService; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.WorkbenchEncoding; +import org.osgi.framework.Bundle; + +/** + * Serial launcher delegate implementation. + */ +@SuppressWarnings("restriction") +public class LocalLauncherDelegate extends AbstractLauncherDelegate { + + private final IMementoHandler mementoHandler = new LocalMementoHandler(); + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#needsUserConfiguration() + */ + @Override + public boolean needsUserConfiguration() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getPanel(org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer) + */ + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return new LocalWizardConfigurationPanel(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#execute(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void execute(Map properties, ITerminalService.Done done) { + Assert.isNotNull(properties); + + // Set the terminal tab title + String terminalTitle = getTerminalTitle(properties); + if (terminalTitle != null) { + properties.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle); + } + + // If not configured, set the default encodings for the local terminal + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_ENCODING)) { + String encoding = null; + // Set the default encoding: + // Default UTF-8 on Mac or Windows for Local, Preferences:Platform encoding otherwise + if (Platform.OS_MACOSX.equals(Platform.getOS()) || Platform.OS_WIN32.equals(Platform.getOS())) { + encoding = "UTF-8"; //$NON-NLS-1$ + } else { + encoding = WorkbenchEncoding.getWorkbenchDefaultEncoding(); + } + if (encoding != null && !"".equals(encoding)) properties.put(ITerminalsConnectorConstants.PROP_ENCODING, encoding); //$NON-NLS-1$ + } + + // For local terminals, force a new terminal tab each time it is launched, + // if not set otherwise from outside + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_FORCE_NEW)) { + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, Boolean.TRUE); + } + + // Initialize the local terminal working directory. + // By default, start the local terminal in the users home directory + String initialCwd = org.eclipse.tm.terminal.view.ui.activator.UIPlugin.getScopedPreferences().getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD); + String cwd = null; + if (initialCwd == null || IPreferenceKeys.PREF_INITIAL_CWD_USER_HOME.equals(initialCwd) || "".equals(initialCwd.trim())) { //$NON-NLS-1$ + cwd = System.getProperty("user.home"); //$NON-NLS-1$ + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_HOME.equals(initialCwd)) { + String eclipseHomeLocation = System.getProperty("eclipse.home.location"); //$NON-NLS-1$ + if (eclipseHomeLocation != null) { + try { + URI uri = URIUtil.fromString(eclipseHomeLocation); + File f = URIUtil.toFile(uri); + cwd = f.getAbsolutePath(); + } catch (URISyntaxException ex) { /* ignored on purpose */ } + } + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_WS.equals(initialCwd)) { + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + if (org.eclipse.core.resources.ResourcesPlugin.getWorkspace() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation() != null) { + cwd = org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString(); + } + } + } else { + try { + // Resolve possible dynamic variables + IStringVariableManager vm = VariablesPlugin.getDefault().getStringVariableManager(); + String resolved = vm.performStringSubstitution(initialCwd); + + IPath p = new Path(resolved); + if (p.toFile().canRead() && p.toFile().isDirectory()) { + cwd = p.toOSString(); + } + } catch (CoreException ex) { + if (Platform.inDebugMode()) { + UIPlugin.getDefault().getLog().log(ex.getStatus()); + } + } + } + + if (cwd != null && !"".equals(cwd)) { //$NON-NLS-1$ + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, cwd); + } + + // If the current selection resolved to an folder, default the working directory + // to that folder and update the terminal title + ISelectionService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); + if ((service != null && service.getSelection() != null) || properties.containsKey(ITerminalsConnectorConstants.PROP_SELECTION)) { + ISelection selection = (ISelection)properties.get(ITerminalsConnectorConstants.PROP_SELECTION); + if (selection == null) selection = service.getSelection(); + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + String dir = null; + Iterator iter = ((IStructuredSelection)selection).iterator(); + while (iter.hasNext()) { + Object element = iter.next(); + + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + // If the element is not an IResource, try to adapt to IResource + if (!(element instanceof org.eclipse.core.resources.IResource)) { + Object adapted = element instanceof IAdaptable ? ((IAdaptable)element).getAdapter(org.eclipse.core.resources.IResource.class) : null; + if (adapted == null) adapted = Platform.getAdapterManager().getAdapter(element, org.eclipse.core.resources.IResource.class); + if (adapted != null) element = adapted; + } + + if (element instanceof org.eclipse.core.resources.IResource && ((org.eclipse.core.resources.IResource)element).exists()) { + IPath location = ((org.eclipse.core.resources.IResource)element).getLocation(); + if (location == null) continue; + if (location.toFile().isFile()) location = location.removeLastSegments(1); + if (location.toFile().isDirectory() && location.toFile().canRead()) { + dir = location.toFile().getAbsolutePath(); + break; + } + } + + if (element instanceof IPath || element instanceof File) { + File f = element instanceof IPath ? ((IPath)element).toFile() : (File)element; + if (f.isDirectory() && f.canRead()) { + dir = f.getAbsolutePath(); + break; + } + } + } + } + if (dir != null) { + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, dir); + + String basename = new Path(dir).lastSegment(); + properties.put(ITerminalsConnectorConstants.PROP_TITLE, basename + " (" + terminalTitle + ")"); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + } + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + + /** + * Returns the terminal title string. + *

+ * The default implementation constructs a title like "Serial <port> (Start time) ". + * + * @return The terminal title string or null. + */ + private String getTerminalTitle(Map properties) { + // Try to see if the user set a title explicitly via the properties map. + String title = getDefaultTerminalTitle(properties); + if (title != null) return title; + + try { + String hostname = InetAddress.getLocalHost().getHostName(); + if (hostname != null && !"".equals(hostname.trim())) { //$NON-NLS-1$ + return hostname; + } + } catch (UnknownHostException e) { /* ignored on purpose */ } + + return "Local"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) { + if (IMementoHandler.class.equals(adapter)) { + return mementoHandler; + } + return super.getAdapter(adapter); + } + + /** + * Returns the default shell to launch. Looks at the environment + * variable "SHELL" first before assuming some default default values. + * + * @return The default shell to launch. + */ + private final File defaultShell() { + String shell = null; + if (Platform.OS_WIN32.equals(Platform.getOS())) { + if (System.getenv("ComSpec") != null && !"".equals(System.getenv("ComSpec").trim())) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + shell = System.getenv("ComSpec").trim(); //$NON-NLS-1$ + } else { + shell = "cmd.exe"; //$NON-NLS-1$ + } + } + if (shell == null) { + shell = org.eclipse.tm.terminal.view.ui.activator.UIPlugin.getScopedPreferences().getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX); + if (shell == null || "".equals(shell)) { //$NON-NLS-1$ + if (System.getenv("SHELL") != null && !"".equals(System.getenv("SHELL").trim())) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + shell = System.getenv("SHELL").trim(); //$NON-NLS-1$ + } else { + shell = "/bin/sh"; //$NON-NLS-1$ + } + } + } + + return new File(shell); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#createTerminalConnector(java.util.Map) + */ + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String)properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) connectorId = "org.eclipse.tm.terminal.connector.local.LocalConnector"; //$NON-NLS-1$ + + // Extract the process properties using defaults + String image; + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_PATH) + || properties.get(ITerminalsConnectorConstants.PROP_PROCESS_PATH) == null) { + File defaultShell = defaultShell(); + image = defaultShell.isAbsolute() ? defaultShell.getAbsolutePath() : defaultShell.getPath(); + } else { + image = (String)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_PATH); + } + + String arguments = (String)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ARGS); + if (arguments == null && !Platform.OS_WIN32.equals(Platform.getOS())) { + arguments = org.eclipse.tm.terminal.view.ui.activator.UIPlugin.getScopedPreferences().getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX_ARGS); + } + + // Determine if a PTY will be used + boolean isUsingPTY = (properties.get(ITerminalsConnectorConstants.PROP_PROCESS_OBJ) == null && PTY.isSupported(PTY.Mode.TERMINAL)) + || properties.get(ITerminalsConnectorConstants.PROP_PTY_OBJ) instanceof PTY; + + boolean localEcho = false; + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_LOCAL_ECHO) + || !(properties.get(ITerminalsConnectorConstants.PROP_LOCAL_ECHO) instanceof Boolean)) { + // On Windows, turn on local echo by default if no PTY is used (bug 433645) + if (Platform.OS_WIN32.equals(Platform.getOS())) { + localEcho = !isUsingPTY; + } + } else { + localEcho = ((Boolean)properties.get(ITerminalsConnectorConstants.PROP_LOCAL_ECHO)).booleanValue(); + } + + String lineSeparator = null; + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR) + || !(properties.get(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR) instanceof String)) { + // No line separator will be set if a PTY is used + if (!isUsingPTY) { + lineSeparator = Platform.OS_WIN32.equals(Platform.getOS()) ? ILineSeparatorConstants.LINE_SEPARATOR_CRLF : ILineSeparatorConstants.LINE_SEPARATOR_LF; + } + } else { + lineSeparator = (String)properties.get(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR); + } + + Process process = (Process)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_OBJ); + PTY pty = (PTY)properties.get(ITerminalsConnectorConstants.PROP_PTY_OBJ); + ITerminalServiceOutputStreamMonitorListener[] stdoutListeners = (ITerminalServiceOutputStreamMonitorListener[])properties.get(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS); + ITerminalServiceOutputStreamMonitorListener[] stderrListeners = (ITerminalServiceOutputStreamMonitorListener[])properties.get(ITerminalsConnectorConstants.PROP_STDERR_LISTENERS); + String workingDir = (String)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR); + + String[] envp = null; + if (properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT) && + properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT) != null && + properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT) instanceof String[]){ + envp = (String[])properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT); + } + + // Set the ECLIPSE_HOME and ECLIPSE_WORKSPACE environment variables + List envpList = new ArrayList(); + if (envp != null) envpList.addAll(Arrays.asList(envp)); + + // ECLIPSE_HOME + String eclipseHomeLocation = System.getProperty("eclipse.home.location"); //$NON-NLS-1$ + if (eclipseHomeLocation != null) { + try { + URI uri = URIUtil.fromString(eclipseHomeLocation); + File f = URIUtil.toFile(uri); + envpList.add("ECLIPSE_HOME=" + f.getAbsolutePath()); //$NON-NLS-1$ + } catch (URISyntaxException e) { /* ignored on purpose */ } + } + + // ECLIPSE_WORKSPACE + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + if (org.eclipse.core.resources.ResourcesPlugin.getWorkspace() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation() != null) { + envpList.add("ECLIPSE_WORKSPACE=" + org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()); //$NON-NLS-1$ + } + } + + // Convert back into a string array + envp = envpList.toArray(new String[envpList.size()]); + + Assert.isTrue(image != null || process != null); + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the process settings + ProcessSettings processSettings = new ProcessSettings(); + processSettings.setImage(image); + processSettings.setArguments(arguments); + processSettings.setProcess(process); + processSettings.setPTY(pty); + processSettings.setLocalEcho(localEcho); + processSettings.setLineSeparator(lineSeparator); + processSettings.setStdOutListeners(stdoutListeners); + processSettings.setStdErrListeners(stderrListeners); + processSettings.setWorkingDir(workingDir); + processSettings.setEnvironment(envp); + + if (properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT)) { + Object value = properties.get(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT); + processSettings.setMergeWithNativeEnvironment(value instanceof Boolean ? ((Boolean)value).booleanValue() : false); + } + + // And save the settings to the store + processSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + return connector; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalLauncherHandler.java b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalLauncherHandler.java new file mode 100644 index 00000000000..d8701cb49b1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalLauncherHandler.java @@ -0,0 +1,80 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.local.launcher; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.ui.IEditorInput; +import org.eclipse.ui.IPathEditorInput; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Local terminal launcher handler implementation. + */ +public class LocalLauncherHandler extends AbstractHandler { + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + // Get the current selection + ISelection selection = HandlerUtil.getCurrentSelection(event); + + // If the selection is not a structured selection, check if there is an active + // editor and get the path from the editor input + if (!(selection instanceof IStructuredSelection)) { + IEditorInput input = HandlerUtil.getActiveEditorInput(event); + if (input instanceof IPathEditorInput) { + IPath path = ((IPathEditorInput)input).getPath(); + if (path != null) { + if (path.toFile().isFile()) path = path.removeLastSegments(1); + if (path.toFile().isDirectory() && path.toFile().canRead()) selection = new StructuredSelection(path); + } + } + } + + // Get all applicable launcher delegates for the current selection + ILauncherDelegate[] delegates = LauncherDelegateManager.getInstance().getApplicableLauncherDelegates(selection); + // Find the local terminal launcher delegate + ILauncherDelegate delegate = null; + for (ILauncherDelegate candidate : delegates) { + if ("org.eclipse.tm.terminal.connector.local.launcher.local".equals(candidate.getId())) { //$NON-NLS-1$ + delegate = candidate; + break; + } + } + + // Launch the local terminal + if (delegate != null) { + Map properties = new HashMap(); + properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, delegate.getId()); + properties.put(ITerminalsConnectorConstants.PROP_SELECTION, selection); + + delegate.execute(properties, null); + } + + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalMementoHandler.java b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalMementoHandler.java new file mode 100644 index 00000000000..d334b946ae9 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.local/src/org/eclipse/tm/terminal/connector/local/launcher/LocalMementoHandler.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.local.launcher; + +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.ui.IMemento; + +/** + * Local terminal connection memento handler implementation. + */ +public class LocalMementoHandler implements IMementoHandler { + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#saveState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void saveState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#restoreState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void restoreState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.classpath b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.options b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.options new file mode 100644 index 00000000000..7e3d5dfe7aa --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.options @@ -0,0 +1 @@ +org.eclipse.tm.terminal.connector.process/debugmode = 0 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.project b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.project new file mode 100644 index 00000000000..92d9bc9fd90 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.project @@ -0,0 +1,45 @@ + + + org.eclipse.tm.terminal.connector.process + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + + + 1329502082911 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..24dad4464e4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,362 @@ +#Tue Oct 11 11:53:38 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.connector.process/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..23d416a1ae2 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/META-INF/MANIFEST.MF @@ -0,0 +1,24 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.connector.process;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Activator: org.eclipse.tm.terminal.connector.process.activator.UIPlugin +Bundle-Vendor: %providerName +Import-Package: org.eclipse.cdt.utils.pty;mandatory:=native, + org.eclipse.cdt.utils.spawner;mandatory:=native +Require-Bundle: org.eclipse.cdt.core;bundle-version="5.6.0";resolution:=optional, + org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.resources;bundle-version="3.8.1";resolution:=optional, + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.view.ui;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.ui;bundle-version="3.8.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.connector.process, + org.eclipse.tm.terminal.connector.process.activator;x-internal:=true, + org.eclipse.tm.terminal.connector.process.help, + org.eclipse.tm.terminal.connector.process.nls;x-internal:=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/META-INF/p2.inf b/terminal/plugins/org.eclipse.tm.terminal.connector.process/META-INF/p2.inf new file mode 100644 index 00000000000..103dc2ce7d5 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/META-INF/p2.inf @@ -0,0 +1,82 @@ +############################################################################### +# Copyright (c) 2014, 2015 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +# Most of the dependencies exposed here are actually covered in the feature.xml +# This file ensures that the current bundle has all it needs, even if installed +# without the enclosing org.eclipse.tm.terminal.view.feature . +# See also https://bugs.eclipse.org/bugs/show_bug.cgi?id=435150 . + +# 1. Make the optional cdt.core dependency non-greedy: Use (or update to proper +# version!) when installed, but do not install automatically since the newer +# org.eclipse.cdt.core.native can satisfy the dependency better. We use this +# trick since CDT 8.3 had no version on export-package yet but we do want +# a version constraint. +requires.0.namespace = org.eclipse.equinox.p2.iu +requires.0.name = org.eclipse.cdt.core +#requires.0.range = [5.6, 6.0) +requires.0.greedy = false +requires.0.optional = true + +#requires.1.namespace = org.eclipse.equinox.p2.iu +#requires.1.name = org.eclipse.cdt.core.native +#requires.1.range = [5.6, 6.0) +#requires.1.greedy = true +#requires.1.optional = true + +# 2. Add the required fragments for local terminal support with proper version. +requires.2.namespace = org.eclipse.equinox.p2.iu +requires.2.name = org.eclipse.cdt.core.aix +#requires.2.range = [5.3, 6.0) +requires.2.filter = (osgi.os=aix) + +requires.3.namespace = org.eclipse.equinox.p2.iu +requires.3.name = org.eclipse.cdt.core.linux +#requires.3.range = [5.2, 6.0) +requires.3.filter = (osgi.os=linux) + +requires.4.namespace = org.eclipse.equinox.p2.iu +requires.4.name = org.eclipse.cdt.core.linux.ppc64 +#requires.4.range = [5.1, 6.0) +requires.4.filter = (&(osgi.os=linux)(osgi.arch=ppc64)) + +#requires.5.namespace = org.eclipse.equinox.p2.iu +#requires.5.name = org.eclipse.cdt.core.linux.x86 +#requires.5.range = [5.2, 6.0) +#requires.5.filter = (&(osgi.os=linux)(osgi.arch=x86)) + +requires.6.namespace = org.eclipse.equinox.p2.iu +requires.6.name = org.eclipse.cdt.core.linux.x86_64 +#requires.6.range = [5.2, 6.0) +requires.6.filter = (&(osgi.os=linux)(osgi.arch=x86_64)) + +requires.7.namespace = org.eclipse.equinox.p2.iu +requires.7.name = org.eclipse.cdt.core.macosx +#requires.7.range = [5.2, 6.0) +requires.7.filter = (osgi.os=macosx) + +requires.8.namespace = org.eclipse.equinox.p2.iu +requires.8.name = org.eclipse.cdt.core.solaris +#requires.8.range = [5.2, 6.0) +requires.8.filter = (&(osgi.os=solaris)(osgi.arch=sparc)) + +requires.9.namespace = org.eclipse.equinox.p2.iu +requires.9.name = org.eclipse.cdt.core.win32 +#requires.9.range = [5.3, 6.0) +requires.9.filter = (osgi.os=win32) + +#requires.10.namespace = org.eclipse.equinox.p2.iu +#requires.10.name = org.eclipse.cdt.core.win32.x86 +#requires.10.range = [5.2, 6.0) +#requires.10.filter = (&(osgi.os=win32)(osgi.arch=x86)) + +requires.11.namespace = org.eclipse.equinox.p2.iu +requires.11.name = org.eclipse.cdt.core.win32.x86_64 +#requires.11.range = [5.2, 6.0) +requires.11.filter = (&(osgi.os=win32)(osgi.arch=x86_64)) diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/about.html b/terminal/plugins/org.eclipse.tm.terminal.connector.process/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

May 24, 2012

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/build.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.process/build.properties new file mode 100644 index 00000000000..41ee77d01c1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/build.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.process/plugin.properties new file mode 100644 index 00000000000..4d5750b57e4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/plugin.properties @@ -0,0 +1,24 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal Process Connector +providerName = Eclipse.org - Target Management + +# ----- Terminal Connectors ----- + +TerminalConnector.process=Process Connector (hidden) + +# ----- Terminal Launcher Delegates ----- + +ProcessLauncherDelegate.label=Streams Terminal + +# ----- Commands and Menu contributions ----- diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.process/plugin.xml new file mode 100644 index 00000000000..4b981ff8272 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/plugin.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.process/pom.xml new file mode 100644 index 00000000000..e51c0e0e903 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.connector.process + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessConnector.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessConnector.java new file mode 100644 index 00000000000..a297da9cd9a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessConnector.java @@ -0,0 +1,318 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Kaloyan Raev - Bug 485658 - NPE prevents displaying the actual error + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process; + +import java.io.File; +import java.io.IOException; +import java.io.StreamTokenizer; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.cdt.utils.spawner.ProcessFactory; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.MessageDialog; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.emulator.VT100Emulator; +import org.eclipse.tm.internal.terminal.emulator.VT100TerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.connector.process.nls.Messages; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ILineSeparatorConstants; +import org.eclipse.tm.terminal.view.core.utils.Env; +import org.eclipse.tm.terminal.view.ui.manager.ConsoleManager; +import org.eclipse.tm.terminal.view.ui.streams.AbstractStreamsConnector; + +/** + * Process connector implementation. + */ +@SuppressWarnings("restriction") +public class ProcessConnector extends AbstractStreamsConnector { + // Reference to the process settings + private final ProcessSettings settings; + + // Reference to the PTY instance. + private PTY pty; + // Reference to the launched process instance. + private Process process; + // Reference to the process monitor + private ProcessMonitor monitor; + + // The terminal width and height. Initially unknown. + private int width = -1; + private int height = -1; + + /** + * Constructor. + */ + public ProcessConnector() { + this(new ProcessSettings()); + } + + /** + * Constructor. + * + * @param settings The process settings. Must not be null + */ + public ProcessConnector(ProcessSettings settings) { + super(); + + Assert.isNotNull(settings); + this.settings = settings; + } + + /** + * Returns the process object or null if the + * connector is connector. + * + * @return The process object or null. + */ + public Process getProcess() { + return process; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#connect(org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl) + */ + @Override + public void connect(ITerminalControl control) { + Assert.isNotNull(control); + super.connect(control); + + pty = null; + width = -1; + height = -1; + + try { + boolean isAnsiTerminal = false; + + // Try to determine process and PTY instance from the process settings + process = settings.getProcess(); + pty = settings.getPTY(); + + // No process -> create PTY on supported platforms and execute + // process image. + if (process == null) { + if (PTY.isSupported(PTY.Mode.TERMINAL)) { + try { + pty = new PTY(PTY.Mode.TERMINAL); + + // Initialize the terminal size + VT100Emulator text = ((VT100TerminalControl)control).getTerminalText(); + text.fontChanged(); + } catch (IOException e) { + // PTY not supported + } + } + + // Build up the command + StringBuilder command = new StringBuilder(settings.getImage()); + String arguments = settings.getArguments(); + if (arguments != null && !"".equals(arguments.trim())) { //$NON-NLS-1$ + // Append to the command now + command.append(" "); //$NON-NLS-1$ + command.append(arguments.trim()); + } + + File workingDir =null; + if (settings.getWorkingDir()!=null){ + workingDir = new File(settings.getWorkingDir()); + } + + String[] envp = null; + if (settings.getEnvironment()!=null){ + envp = settings.getEnvironment(); + } + + if (settings.isMergeWithNativeEnvironment()) { + envp = Env.getEnvironment(envp, true); + } + + isAnsiTerminal = getTermVariable(envp).startsWith("ansi"); //$NON-NLS-1$ + + if (pty != null) { + // A PTY is available -> can use the ProcessFactory. + + // Tokenize the command (ProcessFactory takes an array) + StreamTokenizer st = new StreamTokenizer(new StringReader(command.toString())); + st.resetSyntax(); + st.whitespaceChars(0, 32); + st.whitespaceChars(0xa0, 0xa0); + st.wordChars(33, 255); + st.quoteChar('"'); + st.quoteChar('\''); + + List argv = new ArrayList(); + int ttype = st.nextToken(); + while (ttype != StreamTokenizer.TT_EOF) { + argv.add(st.sval); + ttype = st.nextToken(); + } + + // Execute the process + process = ProcessFactory.getFactory().exec(argv.toArray(new String[argv.size()]), envp, workingDir, pty); + } else { + // No PTY -> just execute via the standard Java Runtime implementation. + process = Runtime.getRuntime().exec(command.toString(), envp, workingDir); + } + } + + String lineSeparator = settings.getLineSeparator(); + if (lineSeparator == null && pty == null) { + lineSeparator = System.getProperty("line.separator"); //$NON-NLS-1$ + if ("\r".equals(lineSeparator)) { //$NON-NLS-1$ + lineSeparator = ILineSeparatorConstants.LINE_SEPARATOR_CR; + } + else if ("\n".equals(lineSeparator)) { //$NON-NLS-1$ + lineSeparator = ILineSeparatorConstants.LINE_SEPARATOR_LF; + } + else { + lineSeparator = ILineSeparatorConstants.LINE_SEPARATOR_CRLF; + } + } + + // Setup the listeners + setStdoutListeners(settings.getStdOutListeners()); + setStderrListeners(settings.getStdErrListeners()); + + // Enable VT100 line wrapping if we are connected via pty + // And TERM is VT100 compatible + if (pty != null && !isAnsiTerminal) + control.setVT100LineWrapping(true); + + // connect the streams + connectStreams(control, process.getOutputStream(), process.getInputStream(), (pty == null ? process.getErrorStream() : null), settings.isLocalEcho(), lineSeparator); + + // Set the terminal control state to CONNECTED + control.setState(TerminalState.CONNECTED); + + // Create the process monitor + monitor = new ProcessMonitor(this); + monitor.startMonitoring(); + } catch (IOException e) { + // Disconnect right away + disconnect(); + // Lookup the tab item + CTabItem item = ConsoleManager.getInstance().findConsole(control); + if (item != null) item.dispose(); + // Get the error message from the exception + String msg = e.getLocalizedMessage() != null ? e.getLocalizedMessage() : ""; //$NON-NLS-1$ + Assert.isNotNull(msg); + // Strip away "Exec_tty error:" + msg = msg.replace("Exec_tty error:", "").trim(); //$NON-NLS-1$ //$NON-NLS-2$ + // Repackage into a more user friendly error + msg = NLS.bind(Messages.ProcessConnector_error_creatingProcess, settings.getImage(), msg); + // Open an error dialog + MessageDialog.openError(control.getShell(), Messages.ProcessConnector_error_title, msg); + } + } + + private static String getTermVariable(String[] envp) { + if (envp != null && !Platform.OS_WIN32.equals(Platform.getOS())) + for (String var : envp) + if (var.startsWith("TERM=")) //$NON-NLS-1$ + return var.substring(5); + return "xterm"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#isLocalEcho() + */ + @Override + public boolean isLocalEcho() { + return settings.isLocalEcho(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.streams.AbstractStreamsConnector#doDisconnect() + */ + @Override + public void doDisconnect() { + // Stop monitoring the process + if (monitor != null) { + monitor.dispose(); + } + + boolean isWindows = Platform.OS_WIN32.equals(Platform.getOS()); + + if (!isWindows) { + // Destroy the process first, except on windows (Bug 465674) + if (process != null) { process.destroy(); process = null; } + } + + // Dispose the streams + super.doDisconnect(); + + if (isWindows) { + // On Windows destroy the process after closing streams + if (process != null) { process.destroy(); process = null; } + } + + // Set the terminal control state to CLOSED. + fControl.setState(TerminalState.CLOSED); + } + + // ***** Process Connector settings handling ***** + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#setDefaultSettings() + */ + @Override + public void setDefaultSettings() { + settings.load(new NullSettingsStore()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getSettingsSummary() + */ + @Override + public String getSettingsSummary() { + return settings.getImage() != null ? settings.getImage() : ""; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#load(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void load(ISettingsStore store) { + settings.load(store); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#save(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void save(ISettingsStore store) { + settings.save(store); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#setTerminalSize(int, int) + */ + @Override + public void setTerminalSize(int newWidth, int newHeight) { + if (width != newWidth || height != newHeight) { + width = newWidth; + height = newHeight; + if (pty != null) { + pty.setTerminalSize(newWidth, newHeight); + } + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessLauncherDelegate.java new file mode 100644 index 00000000000..bc9e067f29d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessLauncherDelegate.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process; + +import java.util.Map; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +/** + * Process launcher delegate implementation. + */ +@SuppressWarnings("restriction") +public class ProcessLauncherDelegate extends AbstractLauncherDelegate { + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#needsUserConfiguration() + */ + @Override + public boolean needsUserConfiguration() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getPanel(org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer) + */ + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#execute(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void execute(Map properties, ITerminalService.Done done) { + Assert.isNotNull(properties); + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#createTerminalConnector(java.util.Map) + */ + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String)properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) connectorId = "org.eclipse.tm.terminal.connector.process.ProcessConnector"; //$NON-NLS-1$ + + // Extract the process properties + String image = (String)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_PATH); + String arguments = (String)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ARGS); + Process process = (Process)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_OBJ); + PTY pty = (PTY)properties.get(ITerminalsConnectorConstants.PROP_PTY_OBJ); + Object value = properties.get(ITerminalsConnectorConstants.PROP_LOCAL_ECHO); + boolean localEcho = value instanceof Boolean ? ((Boolean)value).booleanValue() : false; + String lineSeparator = (String)properties.get(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR); + ITerminalServiceOutputStreamMonitorListener[] stdoutListeners = (ITerminalServiceOutputStreamMonitorListener[])properties.get(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS); + ITerminalServiceOutputStreamMonitorListener[] stderrListeners = (ITerminalServiceOutputStreamMonitorListener[])properties.get(ITerminalsConnectorConstants.PROP_STDERR_LISTENERS); + String workingDir = (String)properties.get(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR); + + String[] envp = null; + if (properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT) && + properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT) != null && + properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT) instanceof String[]){ + envp = (String[])properties.get(ITerminalsConnectorConstants.PROP_PROCESS_ENVIRONMENT); + } + + Assert.isTrue(image != null || process != null); + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the process settings + ProcessSettings processSettings = new ProcessSettings(); + processSettings.setImage(image); + processSettings.setArguments(arguments); + processSettings.setProcess(process); + processSettings.setPTY(pty); + processSettings.setLocalEcho(localEcho); + processSettings.setLineSeparator(lineSeparator); + processSettings.setStdOutListeners(stdoutListeners); + processSettings.setStdErrListeners(stderrListeners); + processSettings.setWorkingDir(workingDir); + processSettings.setEnvironment(envp); + + if (properties.containsKey(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT)) { + value = properties.get(ITerminalsConnectorConstants.PROP_PROCESS_MERGE_ENVIRONMENT); + processSettings.setMergeWithNativeEnvironment(value instanceof Boolean ? ((Boolean)value).booleanValue() : false); + } + + // And save the settings to the store + processSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + return connector; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessMonitor.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessMonitor.java new file mode 100644 index 00000000000..ad509ca1b50 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessMonitor.java @@ -0,0 +1,108 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process; + +import org.eclipse.core.runtime.Assert; + + +/** + * Process monitor implementation. + */ +public class ProcessMonitor { + // Reference to the parent process connector + private final ProcessConnector processConnector; + // Reference to the monitored process + private final Process process; + // Reference to the monitor thread + private Thread thread; + // Flag to mark the monitor disposed + private boolean disposed; + + + /** + * Constructor. + * + * @param processConnector The parent process connector. Must not be null. + */ + public ProcessMonitor(ProcessConnector processConnector) { + super(); + + Assert.isNotNull(processConnector); + this.processConnector = processConnector; + + // Query the monitored process for easier access + this.process = processConnector.getProcess(); + } + + /** + * Dispose the process monitor. + */ + public void dispose() { + // Set the disposed status + disposed = true; + // Not initialized -> return immediately + if (thread == null) return; + + // Copy the reference + final Thread oldThread = thread; + // Unlink the monitor from the thread + thread = null; + // And interrupt the writer thread + oldThread.interrupt(); + } + + /** + * Starts the terminal output stream monitor. + */ + public void startMonitoring() { + // If already initialized -> return immediately + if (thread != null) return; + + // Create a new runnable which is constantly reading from the stream + Runnable runnable = new Runnable() { + @Override + public void run() { + monitorProcess(); + } + }; + + // Create the monitor thread + thread = new Thread(runnable, "Terminal Process Monitor Thread"); //$NON-NLS-1$ + + // Configure the monitor thread + thread.setDaemon(true); + + // Start the processing + thread.start(); + } + + /** + * Monitors the associated system process, waiting for it to terminate, + * and notifies the associated process monitor's. + */ + public void monitorProcess() { + // If already disposed -> return immediately + if (disposed) return; + + try { + // Wait for the monitored process to terminate + process.waitFor(); + } catch (InterruptedException ie) { + // clear interrupted state + Thread.interrupted(); + } finally { + // Dispose the parent process connector + if (!disposed) + processConnector.disconnect(); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessSettings.java new file mode 100644 index 00000000000..4d74734df74 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessSettings.java @@ -0,0 +1,301 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; + +/** + * Process connector settings implementation. + */ +@SuppressWarnings("restriction") +public class ProcessSettings { + // Reference to the process image + private String image; + // Reference to the process arguments (space separated string) + private String arguments; + // Reference to the process object + private Process process; + // Reference to the pseudo terminal object + private PTY pty; + // Flag to control the local echo (defaults to true if + // the PTY is not supported on the current host platform) + private boolean localEcho = !PTY.isSupported(); + // The line separator setting + private String lineSeparator = null; + // The list of stdout output listeners + private ITerminalServiceOutputStreamMonitorListener[] stdoutListeners = null; + // The list of stderr output listeners + private ITerminalServiceOutputStreamMonitorListener[] stderrListeners = null; + // working directory for process + private String workingDir; + // environment + private String[] environment; + // Flag to control if the provided environment is + // automatically merged with the native process environment. + // Defaults to "true". + private boolean mergeWithNativeEnvironment = true; + + /** + * Sets the process image. + * + * @param image The process image or null. + */ + public void setImage(String image) { + this.image = image; + } + + /** + * Returns the process image. + * + * @return The process image or null. + */ + public String getImage() { + return image; + } + + /** + * Sets the process arguments. + *

+ * The arguments are space separated. The caller is responsible for + * correct quoting. + * + * @param arguments The process arguments or null. + */ + public void setArguments(String arguments) { + this.arguments = arguments; + } + + /** + * Returns the process arguments. + * + * @return The process arguments as space separated list or null. + */ + public String getArguments() { + return arguments; + } + + /** + * Sets the process object. + * + * @param image The process object or null. + */ + public void setProcess(Process process) { + this.process = process; + } + + /** + * Returns the process object. + * + * @return The process object or null. + */ + public Process getProcess() { + return process; + } + + /** + * Sets the pseudo terminal object. + * + * @param pty The pseudo terminal or null. + */ + public void setPTY(PTY pty) { + this.pty = pty; + // If the PTY is set to "null", the local echo will be set to "true" + if (pty == null) setLocalEcho(true); + } + + /** + * Returns the pseudo terminal object. + * + * @return The pseudo terminal or null. + */ + public PTY getPTY() { + return pty; + } + + /** + * Sets if the process requires a local echo from the + * terminal widget. + * + * @param value Specify true to enable the local echo, false otherwise. + */ + public void setLocalEcho(boolean value) { + this.localEcho = value; + } + + /** + * Returns true if the process requires a local echo + * from the terminal widget. + * + * @return True if local echo is enabled, false otherwise. + */ + public boolean isLocalEcho() { + return localEcho; + } + + /** + * Sets the process line separator. + * + * @param separator The process line separator null. + */ + public void setLineSeparator(String separator) { + this.lineSeparator = separator; + } + + /** + * Returns the process line separator. + * + * @return The process line separator or null. + */ + public String getLineSeparator() { + return lineSeparator; + } + + /** + * Sets the list of stdout listeners. + * + * @param listeners The list of stdout listeners or null. + */ + public void setStdOutListeners(ITerminalServiceOutputStreamMonitorListener[] listeners) { + this.stdoutListeners = listeners; + } + + /** + * Returns the list of stdout listeners. + * + * @return The list of stdout listeners or null. + */ + public ITerminalServiceOutputStreamMonitorListener[] getStdOutListeners() { + return stdoutListeners; + } + + /** + * Sets the list of stderr listeners. + * + * @param listeners The list of stderr listeners or null. + */ + public void setStdErrListeners(ITerminalServiceOutputStreamMonitorListener[] listeners) { + this.stderrListeners = listeners; + } + + /** + * Returns the list of stderr listeners. + * + * @return The list of stderr listeners or null. + */ + public ITerminalServiceOutputStreamMonitorListener[] getStdErrListeners() { + return stderrListeners; + } + + /** + * Returns the working directory + * + * @return + */ + public String getWorkingDir() { + return this.workingDir; + } + + /** + * Sets the working directory of the process + * + * @param workingDir the absolute path of the working directory + */ + public void setWorkingDir(String workingDir) { + this.workingDir = workingDir; + } + + /** + * Get the process environment + * + * @return + */ + public String[] getEnvironment() { + return environment; + } + + /** + * Sets the process environment + * + * @param environment - will be added to the "parent" environment of the process + */ + public void setEnvironment(String[] environment) { + this.environment = environment; + } + + /** + * Returns if or if not the provided environment is merged with + * the native process environment. + * + * @return True if the provided environment is merged with the native process environment, false otherwise. + */ + public boolean isMergeWithNativeEnvironment() { + return mergeWithNativeEnvironment; + } + + /** + * Sets if or if not the provided environment is merged with the + * native process environment. + * + * @param value True if the provided environment is merged with the native process environment, false otherwise. + */ + public void setMergeWithNativeEnvironment(boolean value) { + this.mergeWithNativeEnvironment = value; + } + + /** + * Loads the process settings from the given settings store. + * + * @param store The settings store. Must not be null. + */ + public void load(ISettingsStore store) { + Assert.isNotNull(store); + image = store.get("Path", null);//$NON-NLS-1$ + arguments = store.get("Arguments", null); //$NON-NLS-1$ + localEcho = Boolean.parseBoolean(store.get("LocalEcho", Boolean.FALSE.toString())); //$NON-NLS-1$ + mergeWithNativeEnvironment = Boolean.parseBoolean(store.get("MergeWithNativeEnvironment", Boolean.FALSE.toString())); //$NON-NLS-1$ + lineSeparator = store.get("LineSeparator", null); //$NON-NLS-1$ + workingDir = store.get("WorkingDir", null); //$NON-NLS-1$ + if (store instanceof SettingsStore) { + process = (Process)((SettingsStore)store).getSettings().get("Process"); //$NON-NLS-1$ + pty = (PTY)((SettingsStore)store).getSettings().get("PTY"); //$NON-NLS-1$ + stdoutListeners = (ITerminalServiceOutputStreamMonitorListener[])((SettingsStore)store).getSettings().get("StdOutListeners"); //$NON-NLS-1$ + stderrListeners = (ITerminalServiceOutputStreamMonitorListener[])((SettingsStore)store).getSettings().get("StdErrListeners"); //$NON-NLS-1$ + environment = (String[])((SettingsStore)store).getSettings().get("Environment"); //$NON-NLS-1$ + } + } + + /** + * Saves the process settings to the given settings store. + * + * @param store The settings store. Must not be null. + */ + public void save(ISettingsStore store) { + Assert.isNotNull(store); + store.put("Path", image);//$NON-NLS-1$ + store.put("Arguments", arguments); //$NON-NLS-1$ + store.put("LocalEcho", Boolean.toString(localEcho)); //$NON-NLS-1$ + store.put("MergeWithNativeEnvironment", Boolean.toString(mergeWithNativeEnvironment)); //$NON-NLS-1$ + store.put("LineSeparator", lineSeparator); //$NON-NLS-1$ + store.put("WorkingDir", workingDir); //$NON-NLS-1$ + if (store instanceof SettingsStore) { + ((SettingsStore)store).getSettings().put("Process", process); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("PTY", pty); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("StdOutListeners", stdoutListeners); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("StdErrListeners", stderrListeners); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("Environment", environment); //$NON-NLS-1$ + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessSettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessSettingsPage.java new file mode 100644 index 00000000000..3b734e318b4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/ProcessSettingsPage.java @@ -0,0 +1,198 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process; + +import org.eclipse.cdt.utils.pty.PTY; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +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.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.PlatformUI; +import org.osgi.framework.Bundle; + +/** + * Process connector settings page implementation. + */ +@SuppressWarnings("restriction") +public class ProcessSettingsPage extends AbstractSettingsPage { + private Text processImageSelectorControl; + private Button processImageSelectorControlButton; + private Text processArgumentsControl; + private Button localEchoSelectorControl; + private Text processWorkingDirControl; + + private final ProcessSettings settings; + + /** + * Constructor. + * + * @param settings + */ + public ProcessSettingsPage(ProcessSettings settings) { + super(); + + Assert.isNotNull(settings); + this.settings = settings; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#createControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + + // The entry fields shall be properly aligned + Composite panel = new Composite(composite, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginWidth = 0; layout.marginHeight = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // Create the process image selector control + Label label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ProcessSettingsPage_processImagePathSelectorControl_label); + + // Text field and browse button are aligned it their own panel + Composite innerPanel = new Composite(panel, SWT.NONE); + layout = new GridLayout(2, false); + layout.marginWidth = 0; layout.marginHeight = 0; + innerPanel.setLayout(layout); + innerPanel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + processImageSelectorControl = new Text(innerPanel, SWT.SINGLE | SWT.BORDER); + processImageSelectorControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + processImageSelectorControlButton = new Button(innerPanel, SWT.PUSH); + processImageSelectorControlButton.setText(Messages.ProcessSettingsPage_processImagePathSelectorControl_button); + processImageSelectorControlButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + onBrowseButtonSelected(e); + } + }); + + // Create the process arguments control + label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ProcessSettingsPage_processArgumentsControl_label); + + processArgumentsControl = new Text(panel, SWT.SINGLE | SWT.BORDER); + processArgumentsControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // Create the process arguments control + label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ProcessSettingsPage_processWorkingDirControl_label); + + processWorkingDirControl = new Text(panel, SWT.SINGLE | SWT.BORDER); + processWorkingDirControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + // Create the local echo check box + localEchoSelectorControl = new Button(composite, SWT.CHECK); + localEchoSelectorControl.setText(Messages.ProcessSettingsPage_localEchoSelectorControl_label); + localEchoSelectorControl.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + localEchoSelectorControl.setSelection(!PTY.isSupported()); + + // Initialize the control content + loadSettings(); + } + + /** + * Called once the user pressed the browse button. + * + * @param e The selection event or null. + */ + protected void onBrowseButtonSelected(SelectionEvent e) { + // Determine the shell + Shell shell = e != null ? e.widget.getDisplay().getActiveShell() : PlatformUI.getWorkbench().getDisplay().getActiveShell(); + + // create a standard file dialog + FileDialog dialog = new FileDialog(shell, SWT.OPEN); + dialog.setText(Messages.ProcessSettingsPage_dialogTitle); + + // the dialog should open within the directory of the currently selected + // file. If no file has been currently selected, it should open within the + // last browsed directory. + String selectedFile = processImageSelectorControl.getText(); + if (selectedFile != null && selectedFile.trim().length() > 0) { + IPath filePath = new Path(selectedFile); + // If the selected file points to an directory, use the directory as is + IPath filterPath = filePath.toFile().isDirectory() ? filePath : filePath.removeLastSegments(1); + String filterFileName = filePath.toFile().isDirectory() || !filePath.toFile().exists() ? null : filePath.lastSegment(); + + if (!filterPath.isEmpty()) { + dialog.setFilterPath(filterPath.toString()); + } + if (filterFileName != null) { + dialog.setFileName(filterFileName); + } + } else { + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + dialog.setFilterPath(org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString()); + } + } + + // Open the dialog + selectedFile = dialog.open(); + if (selectedFile != null) { + processImageSelectorControl.setText(selectedFile); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#saveSettings() + */ + @Override + public void saveSettings() { + settings.setImage(processImageSelectorControl.getText()); + settings.setArguments(processArgumentsControl.getText()); + settings.setLocalEcho(localEchoSelectorControl.getSelection()); + settings.setWorkingDir(processWorkingDirControl.getText()); + settings.setProcess(null); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#loadSettings() + */ + @Override + public void loadSettings() { + processImageSelectorControl.setText(settings.getImage()); + processArgumentsControl.setText(settings.getArguments()); + localEchoSelectorControl.setSelection(settings.isLocalEcho()); + processWorkingDirControl.setText(settings.getWorkingDir()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#validateSettings() + */ + @Override + public boolean validateSettings() { + // The settings are considered valid if the selected process image can be read. + String selectedFile = processImageSelectorControl.getText(); + return selectedFile != null && !"".equals(selectedFile.trim()) && new Path(selectedFile).toFile().canRead(); //$NON-NLS-1$ + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/activator/UIPlugin.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/activator/UIPlugin.java new file mode 100644 index 00000000000..bf236afcf2e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/activator/UIPlugin.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process.activator; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tm.terminal.view.core.tracing.TraceHandler; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class UIPlugin extends AbstractUIPlugin { + // The shared instance + private static UIPlugin plugin; + + // The trace handler instance + private static volatile TraceHandler traceHandler; + + /** + * The constructor + */ + public UIPlugin() { + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static UIPlugin getDefault() { + return plugin; + } + + /** + * Convenience method which returns the unique identifier of this plugin. + */ + public static String getUniqueIdentifier() { + if (getDefault() != null && getDefault().getBundle() != null) { + return getDefault().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.connector.process"; //$NON-NLS-1$ + } + + /** + * Returns the bundles trace handler. + * + * @return The bundles trace handler. + */ + public static TraceHandler getTraceHandler() { + if (traceHandler == null) { + traceHandler = new TraceHandler(getUniqueIdentifier()); + } + return traceHandler; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry) + */ + @Override + protected void initializeImageRegistry(ImageRegistry registry) { + super.initializeImageRegistry(registry); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the Image object instance. + * + * @param key The key the image is registered with. + * @return The Image object instance or null. + */ + public static Image getImage(String key) { + return getDefault().getImageRegistry().get(key); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the ImageDescriptor object instance. + * + * @param key The key the image is registered with. + * @return The ImageDescriptor object instance or null. + */ + public static ImageDescriptor getImageDescriptor(String key) { + return getDefault().getImageRegistry().getDescriptor(key); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/help/IContextHelpIds.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/help/IContextHelpIds.java new file mode 100644 index 00000000000..2d042f346d7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/help/IContextHelpIds.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process.help; + +import org.eclipse.tm.terminal.connector.process.activator.UIPlugin; + + +/** + * Context help id definitions. + */ +public interface IContextHelpIds { + + /** + * UI plug-in common context help id prefix. + */ + public final static String PREFIX = UIPlugin.getUniqueIdentifier() + "."; //$NON-NLS-1$ + + // ***** Message dialog boxes ***** + + /** + * Process connector: Create process failed + */ + public final static String MESSAGE_CREATE_PROCESS_FAILED = PREFIX + ".status.messageCreateProcessFailed"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/nls/Messages.java new file mode 100644 index 00000000000..9e53c53460b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/nls/Messages.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.process.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Process terminal connector plug-in externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.connector.process.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String ProcessConnector_error_title; + public static String ProcessConnector_error_creatingProcess; +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/nls/Messages.properties new file mode 100644 index 00000000000..21f4086135e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.process/src/org/eclipse/tm/terminal/connector/process/nls/Messages.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +ProcessConnector_error_title=Error +ProcessConnector_error_creatingProcess=Failed to execute ''{0}''.\n\nPossibly caused by:\n{1} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.classpath b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.cvsignore b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.cvsignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.project b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.project new file mode 100644 index 00000000000..da3152ba6b3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.project @@ -0,0 +1,34 @@ + + + org.eclipse.tm.terminal.connector.remote + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..94637dfe13b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,61 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +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=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +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.6 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0b831f584d6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,3 @@ +#Thu Dec 07 03:43:08 CET 2006 +eclipse.preferences.version=1 +internal.default.compliance=user diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..e39aae0d49b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/META-INF/MANIFEST.MF @@ -0,0 +1,30 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.connector.remote;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Require-Bundle: org.eclipse.ui, + org.eclipse.core.runtime, + org.eclipse.tm.terminal.control, + org.eclipse.remote.core, + org.eclipse.remote.ui, + org.eclipse.core.resources, + org.eclipse.swt, + org.eclipse.jface, + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.view.ui;bundle-version="4.5.0";resolution:=optional, + org.eclipse.core.expressions +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.eclipse.tm.terminal.connector.remote, + org.eclipse.tm.terminal.connector.remote.controls, + org.eclipse.tm.terminal.connector.remote.internal;x-internal:=true, + org.eclipse.tm.terminal.connector.remote.internal.preferences;x-internal:=true, + org.eclipse.tm.terminal.connector.remote.launcher, + org.eclipse.tm.terminal.connector.remote.nls;x-internal:=true +Bundle-Activator: org.eclipse.tm.terminal.connector.remote.internal.Activator +Bundle-ActivationPolicy: lazy +Eclipse-LazyStart: true +Import-Package: org.eclipse.core.resources, + org.eclipse.ui.ide diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/about.html b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/about.html new file mode 100644 index 00000000000..62cf4ee7eb8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

June 5, 2007

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/build.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/build.properties new file mode 100644 index 00000000000..e6c3165b15a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/build.properties @@ -0,0 +1,17 @@ +############################################################################### +# Copyright (c) 2015, 2018 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.xml,\ + plugin.properties,\ + about.html + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/plugin.properties new file mode 100644 index 00000000000..567c4642d8d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/plugin.properties @@ -0,0 +1,13 @@ +############################################################################### +# Copyright (c) 2015, 2018 IBM Corporation and others. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +############################################################################### +pluginName = Terminal via Remote API Connector +providerName = Eclipse.org - Target Management +connectionName = Remote Services +RemoteTerminalPage.name = Remote Terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/plugin.xml new file mode 100644 index 00000000000..db974b30030 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/plugin.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/pom.xml new file mode 100644 index 00000000000..c820a1d1594 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.connector.remote + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/schema/parsers.exsd b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/schema/parsers.exsd new file mode 100644 index 00000000000..ec8f1d9f32e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/schema/parsers.exsd @@ -0,0 +1,119 @@ + + + + + + + + + + + Extension point that allows a parser to be added to the terminal view. The parser is intended to process output generated by the remote shell and perform an action based on the content. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Unique identifier for this parser + + + + + + + + + + + + + + + + + + + + + + [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/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteSettings.java new file mode 100644 index 00000000000..e0c4671e641 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteSettings.java @@ -0,0 +1,27 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote; + +public interface IRemoteSettings { + public static final String CONNECTION_NAME = "ConnectionName"; //$NON-NLS-1$ + public static final String CONNECTION_TYPE_ID = "ConnectionTypeId"; //$NON-NLS-1$ + + /** + * Get the connection type ID for the connection (e.g. local, ssh, etc.) + * + * @return connection type ID. + */ + String getConnectionTypeId(); + + /** + * Get the connection name for the target system. + * + * @return connection name + */ + String getConnectionName(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteTerminalConstants.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteTerminalConstants.java new file mode 100644 index 00000000000..b58bc867fa6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteTerminalConstants.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote; + +public interface IRemoteTerminalConstants { + public static final String PREF_TERMINAL_SHELL_COMMAND = "TERMINAL_SHELL_COMMAND"; //$NON-NLS-1$ + public static final String PREF_TERMINAL_TYPE = "TERMINAL_TYPE"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteTerminalParser.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteTerminalParser.java new file mode 100644 index 00000000000..dd8670059dc --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/IRemoteTerminalParser.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote; + +import java.io.IOException; + +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteProcess; + +public interface IRemoteTerminalParser { + /** + * Initialize the remote shell. This method will be called after the connection has been initialized. Implementors can assume + * that the connection is open when this is called. + * + * @param connection + * terminal shell connection + * @return IRemoteProcess a remote process corresponding to the remote shell + * @throws IOException + * if the remote shell fails to start for some reason + */ + IRemoteProcess initialize(IRemoteConnection connection) throws IOException; + + /** + * Parse the input stream. This method will be called with a buffer of characters read from the input stream. If the method + * returns true, the characters will be displayed in the terminal view, otherwise they will be ignored. + * + * @param buf + * buffer containing characters from the terminal input stream + * @return true if the characters should be displayed in the terminal + */ + boolean parse(byte[] buf); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/controls/RemoteWizardConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/controls/RemoteWizardConfigurationPanel.java new file mode 100644 index 00000000000..5a8853f3d87 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/controls/RemoteWizardConfigurationPanel.java @@ -0,0 +1,192 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.controls; + +import java.util.Map; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage; +import org.eclipse.tm.terminal.connector.remote.IRemoteSettings; +import org.eclipse.tm.terminal.connector.remote.internal.RemoteConnector; +import org.eclipse.tm.terminal.connector.remote.internal.RemoteSettings; +import org.eclipse.tm.terminal.connector.remote.internal.RemoteSettingsPage; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; + +/** + * Remote wizard configuration panel implementation. + */ +@SuppressWarnings("restriction") +public class RemoteWizardConfigurationPanel extends AbstractExtendedConfigurationPanel { + + private RemoteSettings remoteSettings; + private ISettingsPage remoteSettingsPage; + + /** + * Constructor. + * + * @param container + * The configuration panel container or null. + */ + public RemoteWizardConfigurationPanel(IConfigurationPanelContainer container) { + super(container); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupPanel(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + panel.setLayoutData(data); + + RemoteConnector conn = new RemoteConnector(); + remoteSettings = (RemoteSettings) conn.getRemoteSettings(); + + remoteSettingsPage = new RemoteSettingsPage(remoteSettings); + if (remoteSettingsPage instanceof AbstractSettingsPage) { + ((AbstractSettingsPage) remoteSettingsPage).setHasControlDecoration(true); + } + remoteSettingsPage.createControl(panel); + + // Add the listener to the settings page + remoteSettingsPage.addListener(new ISettingsPage.Listener() { + + @Override + public void onSettingsPageChanged(Control control) { + if (getContainer() != null) { + getContainer().validate(); + } + } + }); + + // Create the encoding selection combo + createEncodingUI(panel, true); + + setControl(panel); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#setupData(java.util.Map) + */ + @Override + public void setupData(Map data) { + if (data == null || remoteSettings == null || remoteSettingsPage == null) { + return; + } + + String value = (String) data.get(IRemoteSettings.CONNECTION_TYPE_ID); + if (value != null) { + remoteSettings.setConnectionTypeId(value); + } + + value = (String) data.get(IRemoteSettings.CONNECTION_NAME); + if (value != null) { + remoteSettings.setConnectionName(value); + } + + value = (String) data.get(ITerminalsConnectorConstants.PROP_ENCODING); + if (value != null) { + setEncoding(value); + } + + remoteSettingsPage.loadSettings(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#extractData(java.util.Map) + */ + @Override + public void extractData(Map data) { + if (data == null) { + return; + } + + // set the terminal connector id for remote + data.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, + "org.eclipse.tm.terminal.connector.remote.RemoteConnector"); //$NON-NLS-1$ + + remoteSettingsPage.saveSettings(); + + data.put(IRemoteSettings.CONNECTION_TYPE_ID, remoteSettings.getConnectionTypeId()); + data.put(IRemoteSettings.CONNECTION_NAME, remoteSettings.getConnectionName()); + if (getEncoding() != null) { + data.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + } + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#fillSettingsForHost(java.lang.String) + */ + @Override + protected void fillSettingsForHost(String host) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#saveSettingsForHost(boolean) + */ + @Override + protected void saveSettingsForHost(boolean add) { + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#isValid() + */ + @Override + public boolean isValid() { + return isEncodingValid() && remoteSettingsPage.validateSettings(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#doSaveWidgetValues(org.eclipse.jface.dialogs. + * IDialogSettings, java.lang.String) + */ + @Override + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + saveSettingsForHost(true); + super.doSaveWidgetValues(settings, idPrefix); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#getHostFromSettings() + */ + @Override + protected String getHostFromSettings() { + remoteSettingsPage.saveSettings(); + return null; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/Activator.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/Activator.java new file mode 100644 index 00000000000..4ab951914e8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/Activator.java @@ -0,0 +1,125 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Plugin; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.tm.terminal.connector.remote.nls.Messages; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; + +/** + * The activator class controls the plug-in life cycle + */ +public class Activator extends Plugin { + + public static final String PLUGIN_ID = "org.eclipse.tm.terminal.remote"; //$NON-NLS-1$ + private static Activator plugin; + + /** + * The constructor + */ + public Activator() { + super(); + plugin = this; + } + + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + } + + @Override + 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; + } + + /** + * Returns an image descriptor for the image file at the given plug-in relative path. + * + * @param path + * the path + * @return the image descriptor + */ + public static ImageDescriptor getImageDescriptor(String path) { + return AbstractUIPlugin.imageDescriptorFromPlugin(PLUGIN_ID, path); + } + + /** + * Create log entry from an IStatus + * + * @param status + * status to log + */ + public static void log(IStatus status) { + getDefault().getLog().log(status); + } + + /** + * Create log entry from a string + * + * @param msg + * message to log + */ + public static void log(String msg) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, msg, null)); + } + + /** + * Create log entry from a Throwable + * + * @param e + * throwable to log + */ + public static void log(Throwable e) { + log(new Status(IStatus.ERROR, getUniqueIdentifier(), IStatus.ERROR, Messages.TERMINAL_EXCEPTION, e)); + } + + // Get rid of edu.lsu.cct tags + + /** + * Generate a unique identifier + * + * @return unique identifier string + */ + public static String getUniqueIdentifier() { + if (getDefault() == null) { + // If the default instance is not yet initialized, + // return a static identifier. This identifier must + // match the plugin id defined in plugin.xml + return PLUGIN_ID; + } + return getDefault().getBundle().getSymbolicName(); + } + + /** + * Return the OSGi service with the given service interface. + * + * @param service + * service interface + * @return the specified service or null if it's not registered + */ + public static T getService(Class service) { + final BundleContext context = plugin.getBundle().getBundleContext(); + final ServiceReference ref = context.getServiceReference(service); + return ref != null ? context.getService(ref) : null; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/ArgumentParser.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/ArgumentParser.java new file mode 100644 index 00000000000..59d647b9ef6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/ArgumentParser.java @@ -0,0 +1,363 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal; + +import java.text.CharacterIterator; +import java.text.StringCharacterIterator; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Iterator; +import java.util.List; + +/** + * Utility class for managing command line arguments. + */ +public class ArgumentParser { + private final List tokens; + + /** + * Create a command line representation from the string with a shell command + * line. The command line is parsed and split on spaces. Quoted or escaped + * spaces are preserved.. + */ + public ArgumentParser(String commandline) { + this.tokens = parseCommandline(commandline); + } + + /** + * Create a command line representation from an array of strings. The first + * element of the array is assumed to be the command, the remaining, the + * arguments. The elements are not parsed not (un)escaped., but taked as the + * are. + */ + public ArgumentParser(String tokenArray[]) { + this(Arrays.asList(tokenArray)); + } + + /** + * Create a command line representation from an array of strings. The first + * element of the list is assumed to be the command, the remaining, the + * arguments. The elements are not parsed not (un)escaped., but taked as the + * are. + */ + public ArgumentParser(List tokenList) { + this.tokens = new ArrayList(tokenList); + } + + /** + * Create a command line representation from the command and an array of + * parameters. The elements are not parsed not (un)escaped., but taked as + * the are. + */ + public ArgumentParser(String command, String parameterArray[]) { + this(command, Arrays.asList(parameterArray)); + } + + /** + * Create a command line representation from the command and an list of + * parameters. The elements are not parsed not (un)escaped., but taked as + * the are. + */ + public ArgumentParser(String command, List parameterList) { + this.tokens = new ArrayList(); + this.tokens.add(command); + this.tokens.addAll(parameterList); + } + + private static List parseCommandline(String commandline) { + ArrayList result = new ArrayList(); + StringCharacterIterator iterator = new StringCharacterIterator(commandline); + + for (iterator.first(); iterator.current() != CharacterIterator.DONE; iterator.next()) { + + // Restart to skip white space + if (Character.isWhitespace(iterator.current())) { + continue; + } + + // Read token + StringBuffer buffer = new StringBuffer(); + token_reader: for (; iterator.current() != CharacterIterator.DONE; iterator.next()) { + char tokenChar = iterator.current(); + + // A white space terminates the token + if (Character.isWhitespace(tokenChar)) { + break token_reader; + } + + // Handle character that composes the token + switch (tokenChar) { + case '"': { + /* + * Read all text within double quotes or until end of + * string. Allows escaping. + */ + iterator.next(); // Skip quote + quoted_reader: while ((iterator.current() != CharacterIterator.DONE) && (iterator.current() != '"')) { + char innerChar = iterator.current(); + switch (innerChar) { + case '\\': + char nextChar = iterator.next(); + switch (nextChar) { + case CharacterIterator.DONE: + break quoted_reader; + case '"': + // Add the character, but remove the escape + buffer.append(nextChar); + iterator.next(); + continue quoted_reader; + default: + // Add the character and keep escape + buffer.append(innerChar); + buffer.append(nextChar); + iterator.next(); + continue quoted_reader; + } + default: + buffer.append(innerChar); + iterator.next(); + continue quoted_reader; + } + } + continue token_reader; + } + case '\'': { + /* + * Read all text within single quotes or until end of + * string. No escaping. + */ + iterator.next(); // Skip the quote + while ((iterator.current() != CharacterIterator.DONE) && (iterator.current() != '\'')) { + buffer.append(iterator.current()); + iterator.next(); + } + continue token_reader; + } + case '\\': { + /* + * Read escaped char. + */ + char nextChar = iterator.next(); + switch (nextChar) { + case CharacterIterator.DONE: + break token_reader; + case '\n': + // Ignore newline. Both lines are concatenated. + continue token_reader; + default: + // Add the character, but remove the escape + buffer.append(nextChar); + continue token_reader; + } + } + default: + /* + * Any other char, add to the buffer. + */ + buffer.append(tokenChar); + continue token_reader; + } + } + result.add(buffer.toString()); + } + + return result; + } + + /** + * Convert all tokens in a full command line that can be executed in a + * shell. + * + * @param fullEscape + * If every special character shall be escaped. If false, only + * white spaces are escaped and the shell will interpret the + * special chars. If true, then all special chars are quoted. + */ + public String getCommandLine(boolean fullEscape) { + StringBuffer buffer = new StringBuffer(); + Iterator iterator = this.tokens.iterator(); + boolean first = true; + while (iterator.hasNext()) { + String token = iterator.next(); + if (!first) { + buffer.append(' '); + } else { + first = false; + } + buffer.append(escapeToken(token, fullEscape)); + } + return buffer.toString(); + } + + private StringBuffer escapeToken(String token, boolean fullEscape) { + StringBuffer buffer = new StringBuffer(); + StringCharacterIterator iter = new StringCharacterIterator(token); + for (char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) { + if (Character.isWhitespace(c)) { + buffer.append('\\'); + buffer.append(c); + continue; + } + switch (c) { + case '(': + case ')': + case '[': + case ']': + case '{': + case '}': + case '|': + case '\\': + case '*': + case '&': + case '^': + case '%': + case '$': + case '#': + case '@': + case '!': + case '~': + case '`': + case '\'': + case '"': + case ':': + case ';': + case '?': + case '>': + case '<': + case '\n': + if (fullEscape) { + buffer.append('\\'); + } + buffer.append(c); + continue; + case ' ': + buffer.append('\\'); + buffer.append(c); + continue; + default: + buffer.append(c); + continue; + } + } + return buffer; + } + + /** + * Returns a List of all entries of the command line. + * + * @return The Array + */ + public String[] getTokenArray() { + return this.tokens.toArray(new String[this.tokens.size()]); + } + + /** + * Returns a List of all entries of the command line. + * + * @return The List + */ + public List getTokenList() { + return new ArrayList(this.tokens); + } + + /** + * Returns the command of the command line, assuming that the first entry is + * always the command. + * + * @return The command or null if the command lines has no command nor + * arguments. + */ + public String getCommand() { + if (this.tokens.size() == 0) { + return null; + } + return this.tokens.get(0); + } + + /** + * Returns the command of the command line, assuming that the first entry is + * always the command. + * + * @return The command or null if the command lines has no command nor + * arguments. + * @param fullEscape + * If every special character shall be escaped. If false, only + * white spaces are escaped and the shell will interpret the + * special chars. If true, then all special chars are quoted. + */ + public String getEscapedCommand(boolean fullEscape) { + if (this.tokens.size() == 0) { + return null; + } + return escapeToken(this.tokens.get(0), fullEscape).toString(); + } + + /** + * Returns a list of all arguments, assuming that the first entry is the + * command name. + * + * @return The Array or null if the command lines has no command nor + * arguments. + */ + public String[] getParameterArray() { + if (this.tokens.size() == 0) { + return null; + } + return this.tokens.subList(1, this.tokens.size()).toArray(new String[this.tokens.size() - 1]); + } + + /** + * Returns a list of all arguments, assuming that the first entry is the + * command name. + * + * @return The List or null if the command lines has no command nor + * arguments. + */ + public List getParameterList() { + if (this.tokens.size() == 0) { + return null; + } + return new ArrayList(this.tokens.subList(1, this.tokens.size())); + } + + /** + * Returns the total number of entries. + * + * @return the total number of entries + */ + public int getSize() { + return this.tokens.size(); + } + + /** + * Returns a representation of the command line for debug purposes. + */ + @Override + public String toString() { + StringBuffer buffer = new StringBuffer(); + buffer.append("<"); //$NON-NLS-1$ + Iterator iterator = this.tokens.iterator(); + boolean first = true; + while (iterator.hasNext()) { + String token = iterator.next(); + if (!first) { + buffer.append('\n'); + } else { + first = false; + } + buffer.append(token); + } + buffer.append(">"); //$NON-NLS-1$ + return buffer.toString(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteConnectionManager.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteConnectionManager.java new file mode 100644 index 00000000000..93279eadf3b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteConnectionManager.java @@ -0,0 +1,200 @@ +/******************************************************************************* + * Copyright (c) 2015,2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal; + +import java.io.IOException; +import java.io.InputStream; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.RegistryFactory; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.osgi.util.NLS; +import org.eclipse.remote.core.IRemoteCommandShellService; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteProcess; +import org.eclipse.remote.core.IRemoteProcessBuilder; +import org.eclipse.remote.core.IRemoteProcessService; +import org.eclipse.remote.core.IRemoteProcessTerminalService; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.remote.core.exception.RemoteConnectionException; +import org.eclipse.tm.internal.terminal.emulator.VT100Emulator; +import org.eclipse.tm.internal.terminal.emulator.VT100TerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.connector.remote.IRemoteTerminalConstants; +import org.eclipse.tm.terminal.connector.remote.IRemoteTerminalParser; +import org.eclipse.tm.terminal.connector.remote.nls.Messages; + +@SuppressWarnings("restriction") +public class RemoteConnectionManager extends Job { + private final static String PARSERS_EXTENSION_POINT = "parsers"; //$NON-NLS-1$ + private final static String PARSER_ELEMENT = "parser"; //$NON-NLS-1$ + + private static int fgNo; + + private final ITerminalControl control; + private final RemoteConnector connector; + + private IRemoteTerminalParser parser; + private IRemoteProcess remoteProcess; + + protected RemoteConnectionManager(RemoteConnector conn, ITerminalControl control) { + super("Remote Terminal-" + fgNo++); //$NON-NLS-1$ + this.control = control; + this.connector = conn; + setSystem(true); + loadParserExtension(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) + */ + @Override + protected IStatus run(IProgressMonitor monitor) { + IRemoteConnection remoteConnection = null; + + try { + IRemoteServicesManager svcMgr = Activator.getService(IRemoteServicesManager.class); + String connTypeId = connector.getRemoteSettings().getConnectionTypeId(); + IRemoteConnectionType connType = svcMgr.getConnectionType(connTypeId); + if (connType != null) { + remoteConnection = connType.getConnection(connector.getRemoteSettings().getConnectionName()); + } + if (remoteConnection == null) { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), + NLS.bind(Messages.RemoteConnectionManager_0, connector.getRemoteSettings().getConnectionName())); + } + + if (!remoteConnection.isOpen()) { + remoteConnection.open(monitor); + if (!remoteConnection.isOpen()) { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), + NLS.bind(Messages.RemoteConnectionManager_1, connector.getRemoteSettings().getConnectionName())); + } + } + + if (parser != null) { + remoteProcess = parser.initialize(remoteConnection); + } + + if (remoteProcess == null) { + /* + * Check the terminal shell command preference. If the preference is empty and we support a command shell, + * just use that. Otherwise use the preference value if it is set, or fall back to a default if not. + */ + IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(Activator.getUniqueIdentifier()); + String terminalShellCommand = prefs.get(IRemoteTerminalConstants.PREF_TERMINAL_SHELL_COMMAND, ""); //$NON-NLS-1$ + if ("".equals(terminalShellCommand) //$NON-NLS-1$ + && remoteConnection.hasService(IRemoteCommandShellService.class)) { + IRemoteCommandShellService cmdShellSvc = remoteConnection.getService(IRemoteCommandShellService.class); + synchronized (this) { + remoteProcess = cmdShellSvc.getCommandShell(IRemoteProcessBuilder.ALLOCATE_PTY); + } + } else if (remoteConnection.hasService(IRemoteProcessService.class)) { + if ("".equals(terminalShellCommand)) { //$NON-NLS-1$ + terminalShellCommand = "/bin/bash -l"; //$NON-NLS-1$ + } + IRemoteProcessService procSvc = remoteConnection.getService(IRemoteProcessService.class); + IRemoteProcessBuilder processBuilder = procSvc + .getProcessBuilder(new ArgumentParser(terminalShellCommand).getTokenList()); + remoteProcess = processBuilder.start(IRemoteProcessBuilder.ALLOCATE_PTY); + } else { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), Messages.RemoteConnectionManager_2); + } + } + + control.setVT100LineWrapping(true); + connector.setInputStream(remoteProcess.getInputStream()); + control.setState(TerminalState.CONNECTED); + control.setTerminalTitle(remoteConnection.getName()); + connector.setOutputStream(remoteProcess.getOutputStream()); + // Initialize terminal size + VT100Emulator text = ((VT100TerminalControl) control).getTerminalText(); + text.fontChanged(); + + // read data until the connection gets terminated + readData(connector.getInputStream()); + } catch (IOException e) { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage()); + } catch (RemoteConnectionException e) { + return new Status(IStatus.ERROR, Activator.getUniqueIdentifier(), e.getMessage()); + } finally { + // make sure the terminal is disconnected when the thread ends + connector.disconnect(); + } + return Status.OK_STATUS; + } + + @Override + protected void canceling() { + super.canceling(); + synchronized (this) { + if (remoteProcess != null && !remoteProcess.isCompleted()) { + remoteProcess.destroy(); + } + } + } + + public void setTerminalSize(int cols, int rows, int width, int height) { + if (remoteProcess != null) { + IRemoteProcessTerminalService termSvc = remoteProcess.getService(IRemoteProcessTerminalService.class); + if (termSvc != null) { + termSvc.setTerminalSize(cols, rows, width, height); + } + } + } + + /** + * Read the data from the connection and display it in the terminal. + * + * @param in + * @throws IOException + */ + private void readData(InputStream in) throws IOException { + byte[] buf = new byte[32 * 1024]; + int n; + while ((n = in.read(buf, 0, buf.length)) >= 0) { + if (n != 0 && (parser == null || parser.parse(buf))) { + control.getRemoteToTerminalOutputStream().write(buf, 0, n); + } + } + } + + private void loadParserExtension() { + IExtensionPoint point = RegistryFactory.getRegistry().getExtensionPoint(Activator.getUniqueIdentifier(), + PARSERS_EXTENSION_POINT); + if (point != null) { + IExtension[] extensions = point.getExtensions(); + for (IExtension extension : extensions) { + IConfigurationElement[] elements = extension.getConfigurationElements(); + for (IConfigurationElement element : elements) { + if (PARSER_ELEMENT.equals(element.getName())) { + try { + parser = (IRemoteTerminalParser) element.createExecutableExtension("class"); //$NON-NLS-1$ + } catch (CoreException e) { + Activator.log(e); + } + } + } + } + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteConnector.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteConnector.java new file mode 100644 index 00000000000..18b3ec59acc --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteConnector.java @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; +import org.eclipse.tm.terminal.connector.remote.IRemoteSettings; + +@SuppressWarnings("restriction") +public class RemoteConnector extends TerminalConnectorImpl { + private OutputStream fOutputStream; + private InputStream fInputStream; + private RemoteConnectionManager fConnection; + private int fWidth; + private int fHeight; + private final RemoteSettings fSettings; + + public RemoteConnector() { + this(new RemoteSettings()); + } + + public RemoteConnector(RemoteSettings settings) { + fSettings = settings; + } + + /* + * (non-Javadoc) + * + * @see + * org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#connect(org.eclipse.tm.internal.terminal. + * provisional.api.ITerminalControl) + */ + @Override + public void connect(ITerminalControl control) { + super.connect(control); + fControl.setState(TerminalState.CONNECTING); + fConnection = new RemoteConnectionManager(this, control); + fConnection.schedule(); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#doDisconnect() + */ + @Override + public synchronized void doDisconnect() { + fConnection.cancel(); + } + + public InputStream getInputStream() { + return fInputStream; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getSettingsSummary() + */ + @Override + public String getSettingsSummary() { + return fSettings.getSummary(); + } + + /** + * Return the Remote Settings. + * + * @return the settings for a concrete connection. + */ + public IRemoteSettings getRemoteSettings() { + return fSettings; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getTerminalToRemoteStream() + */ + @Override + public OutputStream getTerminalToRemoteStream() { + return fOutputStream; + } + + @Override + public void load(ISettingsStore store) { + fSettings.load(store); + } + + @Override + public void setDefaultSettings() { + fSettings.load(new NullSettingsStore()); + } + + @Override + public void save(ISettingsStore store) { + fSettings.save(store); + } + + public void setInputStream(InputStream inputStream) { + fInputStream = inputStream; + } + + public void setOutputStream(OutputStream outputStream) { + fOutputStream = outputStream; + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#setTerminalSize(int, int) + */ + @Override + public void setTerminalSize(int newWidth, int newHeight) { + if (fConnection != null && (newWidth != fWidth || newHeight != fHeight)) { + // avoid excessive communications due to change size requests by caching previous size + fConnection.setTerminalSize(newWidth, newHeight, 8 * newWidth, 8 * newHeight); + fWidth = newWidth; + fHeight = newHeight; + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteSettings.java new file mode 100644 index 00000000000..37dae29bf91 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteSettings.java @@ -0,0 +1,63 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.terminal.connector.remote.IRemoteSettings; + +@SuppressWarnings("restriction") +public class RemoteSettings implements IRemoteSettings { + protected String connectionTypeId; + protected String connectionName; + + public RemoteSettings() { + } + + @Override + public String getConnectionName() { + return connectionName; + } + + @Override + public String getConnectionTypeId() { + return connectionTypeId; + } + + public String getSummary() { + return "Remote:" + getConnectionTypeId() + '_' + getConnectionName(); //$NON-NLS-1$ + } + + @Override + public String toString() { + return getSummary(); + } + + /** + * Load information into the RemoteSettings object. + */ + public void load(ISettingsStore store) { + connectionTypeId = store.get(CONNECTION_TYPE_ID, ""); //$NON-NLS-1$ + connectionName = store.get(CONNECTION_NAME, ""); //$NON-NLS-1$ + } + + /** + * Extract information from the RemoteSettings object. + */ + public void save(ISettingsStore store) { + store.put(CONNECTION_TYPE_ID, connectionTypeId); + store.put(CONNECTION_NAME, connectionName); + } + + public void setConnectionName(String name) { + connectionName = name; + } + + public void setConnectionTypeId(String id) { + connectionTypeId = id; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteSettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteSettingsPage.java new file mode 100644 index 00000000000..8a5958027da --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/RemoteSettingsPage.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2015,2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal; + +import java.util.List; + +import org.eclipse.remote.core.IRemoteCommandShellService; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.remote.ui.widgets.RemoteConnectionWidget; +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.Composite; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.ServiceReference; + +@SuppressWarnings("restriction") +public class RemoteSettingsPage extends AbstractSettingsPage { + private final RemoteSettings fTerminalSettings; + private RemoteConnectionWidget fRemoteConnectionWidget; + + public RemoteSettingsPage(RemoteSettings settings) { + fTerminalSettings = settings; + } + + @Override + public void saveSettings() { + if (fTerminalSettings != null && fRemoteConnectionWidget != null && !fRemoteConnectionWidget.isDisposed()) { + if (fRemoteConnectionWidget.getConnection() != null) { + if (fRemoteConnectionWidget.getConnection().getConnectionType() != null) { + fTerminalSettings.setConnectionTypeId(fRemoteConnectionWidget.getConnection().getConnectionType().getId()); + } + fTerminalSettings.setConnectionName(fRemoteConnectionWidget.getConnection().getName()); + } + } + } + + @Override + public void loadSettings() { + if (fTerminalSettings != null && fRemoteConnectionWidget != null && !fRemoteConnectionWidget.isDisposed()) { + fRemoteConnectionWidget.setConnection(fTerminalSettings.getConnectionTypeId(), fTerminalSettings.getConnectionName()); + } + } + + String get(String value, String def) { + if (value == null || value.length() == 0) { + return def; + } + return value; + } + + @Override + public boolean validateSettings() { + if (fRemoteConnectionWidget == null || fRemoteConnectionWidget.isDisposed() + || fRemoteConnectionWidget.getConnection() == null) { + return false; + } + return true; + } + + @Override + 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); + + BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext(); + ServiceReference ref = context.getServiceReference(IRemoteServicesManager.class); + IRemoteServicesManager manager = context.getService(ref); + @SuppressWarnings("unchecked") + List types = manager.getConnectionTypesSupporting(IRemoteCommandShellService.class); + + fRemoteConnectionWidget = new RemoteConnectionWidget(composite, SWT.NONE, null, 0, types); + fRemoteConnectionWidget.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + fireListeners(fRemoteConnectionWidget); + } + }); + loadSettings(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/preferences/RemoteTerminalPreferenceInitializer.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/preferences/RemoteTerminalPreferenceInitializer.java new file mode 100644 index 00000000000..d8a159c8e47 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/preferences/RemoteTerminalPreferenceInitializer.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.tm.terminal.connector.remote.IRemoteTerminalConstants; +import org.eclipse.tm.terminal.connector.remote.internal.Activator; + +public class RemoteTerminalPreferenceInitializer extends AbstractPreferenceInitializer { + + public RemoteTerminalPreferenceInitializer() { + } + + @Override + public void initializeDefaultPreferences() { + IEclipsePreferences defaultPrefs = DefaultScope.INSTANCE.getNode(Activator.getUniqueIdentifier()); + defaultPrefs.put(IRemoteTerminalConstants.PREF_TERMINAL_SHELL_COMMAND, ""); //$NON-NLS-1$ + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/preferences/RemoteTerminalPreferencePage.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/preferences/RemoteTerminalPreferencePage.java new file mode 100644 index 00000000000..615611aedfd --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/internal/preferences/RemoteTerminalPreferencePage.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.internal.preferences; + +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.preference.StringFieldEditor; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.terminal.connector.remote.IRemoteTerminalConstants; +import org.eclipse.tm.terminal.connector.remote.internal.Activator; +import org.eclipse.tm.terminal.connector.remote.nls.Messages; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.eclipse.ui.preferences.ScopedPreferenceStore; + +public class RemoteTerminalPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + @Override + protected void createFieldEditors() { + Composite parent = getFieldEditorParent(); + addField(new StringFieldEditor(IRemoteTerminalConstants.PREF_TERMINAL_TYPE, "Terminal Type", parent)); + addField(new StringFieldEditor(IRemoteTerminalConstants.PREF_TERMINAL_SHELL_COMMAND, + Messages.RemoteTerminalPreferencePage_0, parent)); + } + + @Override + public IPreferenceStore doGetPreferenceStore() { + return new ScopedPreferenceStore(InstanceScope.INSTANCE, Activator.getUniqueIdentifier()); + } + + @Override + public void init(IWorkbench workbench) { + // Nothing + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/launcher/RemoteLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/launcher/RemoteLauncherDelegate.java new file mode 100644 index 00000000000..32fb70edb39 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/launcher/RemoteLauncherDelegate.java @@ -0,0 +1,179 @@ +/******************************************************************************* + * Copyright (c) 2015,2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.launcher; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.osgi.util.NLS; +import org.eclipse.remote.core.IRemoteConnection; +import org.eclipse.remote.core.IRemoteConnectionType; +import org.eclipse.remote.core.IRemoteServicesManager; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.connector.remote.IRemoteSettings; +import org.eclipse.tm.terminal.connector.remote.controls.RemoteWizardConfigurationPanel; +import org.eclipse.tm.terminal.connector.remote.internal.Activator; +import org.eclipse.tm.terminal.connector.remote.internal.RemoteSettings; +import org.eclipse.tm.terminal.connector.remote.nls.Messages; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +/** + * Remote launcher delegate implementation. + */ +@SuppressWarnings("restriction") +public class RemoteLauncherDelegate extends AbstractLauncherDelegate { + // The Remote terminal connection memento handler + private final IMementoHandler mementoHandler = new RemoteMementoHandler(); + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#needsUserConfiguration() + */ + @Override + public boolean needsUserConfiguration() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getPanel(org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer) + */ + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return new RemoteWizardConfigurationPanel(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#execute(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void execute(Map properties, ITerminalService.Done done) { + Assert.isNotNull(properties); + + // Set the terminal tab title + String terminalTitle = getTerminalTitle(properties); + if (terminalTitle != null) { + properties.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle); + } + + // Force a new terminal tab each time it is launched, if not set otherwise from outside + // TODO need a command shell service routing to get this + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_FORCE_NEW)) { + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, Boolean.TRUE); + } + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + + /** + * Returns the terminal title string. + *

+ * The default implementation constructs a title like "SSH @ host (Start time) ". + * + * @return The terminal title string or null. + */ + private String getTerminalTitle(Map properties) { + // Try to see if the user set a title explicitly via the properties map. + String title = getDefaultTerminalTitle(properties); + if (title != null) return title; + + String connection = (String) properties.get(IRemoteSettings.CONNECTION_NAME); + + if (connection != null) { + DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + String date = format.format(new Date(System.currentTimeMillis())); + return NLS.bind(Messages.RemoteLauncherDelegate_terminalTitle, new String[] { connection, date }); + } + + return Messages.RemoteLauncherDelegate_terminalTitle_default; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ + @SuppressWarnings({ "rawtypes", "unchecked" }) + @Override + public Object getAdapter(Class adapter) { + if (IMementoHandler.class.equals(adapter)) { + return mementoHandler; + } + return super.getAdapter(adapter); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#createTerminalConnector(java.util.Map) + */ + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String) properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) { + connectorId = "org.eclipse.tm.terminal.connector.remote.RemoteConnector"; //$NON-NLS-1$ + } + + // Extract the remote properties + String connTypeId = (String) properties.get(IRemoteSettings.CONNECTION_TYPE_ID); + String connName = (String) properties.get(IRemoteSettings.CONNECTION_NAME); + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the remote settings + RemoteSettings remoteSettings = new RemoteSettings(); + remoteSettings.setConnectionTypeId(connTypeId); + remoteSettings.setConnectionName(connName); + // And save the settings to the store + remoteSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_ENCODING)) { + IRemoteServicesManager svcMgr = Activator.getService(IRemoteServicesManager.class); + + IRemoteConnectionType connType = svcMgr.getConnectionType(connTypeId); + if (connType != null) { + IRemoteConnection remoteConnection = connType.getConnection(connName); + if (remoteConnection != null && remoteConnection.isOpen()) { + properties.put(ITerminalsConnectorConstants.PROP_ENCODING, + remoteConnection.getProperty(IRemoteConnection.LOCALE_CHARMAP_PROPERTY)); + } + } + } + + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_WORKING_DIR, "/tmp"); //$NON-NLS-1$ + + return connector; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/launcher/RemoteMementoHandler.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/launcher/RemoteMementoHandler.java new file mode 100644 index 00000000000..9b478cbc5c1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/launcher/RemoteMementoHandler.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.launcher; + +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.terminal.connector.remote.IRemoteSettings; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.ui.IMemento; + +/** + * Telnet terminal connection memento handler implementation. + */ +public class RemoteMementoHandler implements IMementoHandler { + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#saveState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void saveState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + + // Do not write the terminal title to the memento -> needs to + // be recreated at the time of restoration. + memento.putString(IRemoteSettings.CONNECTION_NAME, (String) properties.get(IRemoteSettings.CONNECTION_NAME)); + memento.putString(IRemoteSettings.CONNECTION_TYPE_ID, (String) properties.get(IRemoteSettings.CONNECTION_TYPE_ID)); + memento.putString(ITerminalsConnectorConstants.PROP_ENCODING, + (String) properties.get(ITerminalsConnectorConstants.PROP_ENCODING)); + } + + /* + * (non-Javadoc) + * + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#restoreState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void restoreState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + + // Restore the terminal properties from the memento + properties.put(IRemoteSettings.CONNECTION_NAME, memento.getString(IRemoteSettings.CONNECTION_NAME)); + properties.put(IRemoteSettings.CONNECTION_TYPE_ID, memento.getString(IRemoteSettings.CONNECTION_TYPE_ID)); + properties.put(ITerminalsConnectorConstants.PROP_ENCODING, memento.getString(ITerminalsConnectorConstants.PROP_ENCODING)); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/nls/Messages.java new file mode 100644 index 00000000000..5a209c22383 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/nls/Messages.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.remote.nls; + +import org.eclipse.osgi.util.NLS; + +public class Messages extends NLS { + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.connector.remote.nls.Messages"; //$NON-NLS-1$ + + public static String RemoteConnectionManager_0; + + public static String RemoteConnectionManager_1; + + public static String RemoteConnectionManager_2; + + public static String RemoteTerminalPreferencePage_0; + + public static String TERMINAL_EXCEPTION; + + public static String RemoteLauncherDelegate_terminalTitle; + public static String RemoteLauncherDelegate_terminalTitle_default; + + static { + // initialize resource bundle + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + private Messages() { + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/nls/Messages.properties new file mode 100644 index 00000000000..35df892f056 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.remote/src/org/eclipse/tm/terminal/connector/remote/nls/Messages.properties @@ -0,0 +1,19 @@ +############################################################################### +# Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +RemoteConnectionManager_0=Unable to create connection: {0} +RemoteConnectionManager_1=Unable to to open connection: {0} +RemoteConnectionManager_2=Connection type does not support the required services +RemoteTerminalPreferencePage_0=Initial Shell Command +TERMINAL_EXCEPTION=Remote Terminal Exception + +RemoteLauncherDelegate_terminalTitle={0} ({1}) +RemoteLauncherDelegate_terminalTitle_default=Remote Terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.classpath b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.options b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.options new file mode 100644 index 00000000000..8ec18dafab2 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.options @@ -0,0 +1 @@ +org.eclipse.tm.terminal.connector.ssh/debugmode = 0 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.project b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.project new file mode 100644 index 00000000000..be963dbfb21 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.project @@ -0,0 +1,45 @@ + + + org.eclipse.tm.terminal.connector.ssh + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + + + 1329502091181 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..4754bba05f6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,362 @@ +#Wed Oct 19 12:10:57 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..983b7c46c0b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/META-INF/MANIFEST.MF @@ -0,0 +1,24 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.connector.ssh;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Activator: org.eclipse.tm.terminal.connector.ssh.activator.UIPlugin +Bundle-Vendor: %providerName +Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.equinox.security;bundle-version="1.1.100", + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.view.ui;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.ui;bundle-version="3.8.0", + com.jcraft.jsch;bundle-version="[0.1.31,1.0.0)", + org.eclipse.jsch.core;bundle-version="[1.0.0,2.0.0)" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.connector.ssh.activator;x-internal:=true, + org.eclipse.tm.terminal.connector.ssh.connector, + org.eclipse.tm.terminal.connector.ssh.controls, + org.eclipse.tm.terminal.connector.ssh.launcher, + org.eclipse.tm.terminal.connector.ssh.nls;x-internal:=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/about.html b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

May 24, 2012

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/build.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/build.properties new file mode 100644 index 00000000000..1c3465df7d0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/build.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + plugin.xml,\ + about.html diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/plugin.properties new file mode 100644 index 00000000000..8cbdd29dbcc --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/plugin.properties @@ -0,0 +1,22 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal SSH Connector +providerName = Eclipse.org - Target Management + +# ----- Terminal Connector ----- + +SshConnector.label=SSH + +# ----- Terminal Launcher Delegates ----- + +SshLauncherDelegate.label=SSH Terminal \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/plugin.xml new file mode 100644 index 00000000000..5c9ea94f3c4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/plugin.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/pom.xml new file mode 100644 index 00000000000..ee95330809b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.connector.ssh + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/activator/UIPlugin.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/activator/UIPlugin.java new file mode 100644 index 00000000000..45b7e429d76 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/activator/UIPlugin.java @@ -0,0 +1,145 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.activator; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.jsch.core.IJSchService; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tm.terminal.connector.ssh.connector.SshConnection; +import org.eclipse.tm.terminal.view.core.tracing.TraceHandler; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; + +/** + * The activator class controls the plug-in life cycle + */ +public class UIPlugin extends AbstractUIPlugin { + // The shared instance + private static UIPlugin plugin; + // The trace handler instance + private static volatile TraceHandler traceHandler; + + // ServiceTracker for IJschService + private ServiceTracker tracker; + + /** + * The constructor + */ + public UIPlugin() { + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static UIPlugin getDefault() { + return plugin; + } + + /** + * Convenience method which returns the unique identifier of this plugin. + */ + public static String getUniqueIdentifier() { + if (getDefault() != null && getDefault().getBundle() != null) { + return getDefault().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.connector.ssh"; //$NON-NLS-1$ + } + + /** + * Returns the bundles trace handler. + * + * @return The bundles trace handler. + */ + public static TraceHandler getTraceHandler() { + if (traceHandler == null) { + traceHandler = new TraceHandler(getUniqueIdentifier()); + } + return traceHandler; + } + + //--------------------------------------------------------------------------- + // + //--------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @SuppressWarnings("unchecked") + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + + tracker = new ServiceTracker(getBundle().getBundleContext(), IJSchService.class.getName(), null); + tracker.open(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + try { + SshConnection.shutdown(); + tracker.close(); + } finally { + plugin = null; + super.stop(context); + } + } + + /** + * Returns an instance of IJSchService from the OSGi Registry. + * @return An instance of IJSchService, or null if no + * IJschService service is available. + */ + public IJSchService getJSchService() { + return (IJSchService)tracker.getService(); + } + + //--------------------------------------------------------------------------- + // + //--------------------------------------------------------------------------- + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry) + */ + @Override + protected void initializeImageRegistry(ImageRegistry registry) { + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the Image object instance. + * + * @param key The key the image is registered with. + * @return The Image object instance or null. + */ + public static Image getImage(String key) { + return getDefault().getImageRegistry().get(key); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the ImageDescriptor object instance. + * + * @param key The key the image is registered with. + * @return The ImageDescriptor object instance or null. + */ + public static ImageDescriptor getImageDescriptor(String key) { + return getDefault().getImageRegistry().getDescriptor(key); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/ISshConstants.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/ISshConstants.java new file mode 100644 index 00000000000..2bcc30b4681 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/ISshConstants.java @@ -0,0 +1,28 @@ +/******************************************************************************* + * Copyright (c) 2000, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Martin Oberhuber (Wind River) - extracted from various team.cvs plugins + * Martin Oberhuber (Wind River) - [175686] Adapted to new IJSchService API + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + + +/** + * Defines the constants used by the terminal.ssh Plugin + */ +public interface ISshConstants { + + // These are from cvs.ui.IHelpContextIds + public static final String CVSUIPREFIX = "org.eclipse.team.cvs.ui."; //$NON-NLS-1$ + public static final String HELP_USER_VALIDATION_DIALOG = CVSUIPREFIX + "user_validation_dialog_context"; //$NON-NLS-1$ + public static final String HELP_KEYBOARD_INTERACTIVE_DIALOG = CVSUIPREFIX + "keyboard_interactive_dialog_context"; //$NON-NLS-1$ + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/ISshSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/ISshSettings.java new file mode 100644 index 00000000000..939addb8116 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/ISshSettings.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Johnson Ma (Wind River) - [218880] Add UI setting for ssh keepalives + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +public interface ISshSettings { + + public static int DEFAULT_SSH_PORT = 22; + + /** + * Get the host name or IP address of remote system to connect. + * @return host name or IP address of the remote system. + */ + String getHost(); + + /** + * Get the login name for connecting to the remote system. + * @return remote login name + */ + String getUser(); + + /** + * Get the password for connecting to the remote system. + * May be empty if connecting via SSH public key authentication + * (with or without passphrase). + * @return password to use + */ + String getPassword(); + + /** + * Get the timeout (in seconds) after which the SSH connection is assumed dead. + * @return timeout (in seconds) for the SSH connection. + */ + int getTimeout(); + + /** + * Get the keepalive interval (in seconds). + * After this time of inactivity, the SSH connector will send a message to the + * remote system in order to avoid timeouts on the remote. A maximum of 6 + * keepalive messages will be sent if enabled. When set to 0, the keepalive + * feature is disabled. + * @return interval (in seconds) for keepalive messages. + */ + int getKeepalive(); + + /** + * Get the TCP/IP port on the remote system to use. + * @return TCP/IP port on the remote system to use. + */ + int getPort(); + + /** + * Return a human-readable String summarizing all relevant connection data. + * This String can be displayed in the Terminal caption, for instance. + * @return a human-readable String summarizing relevant connection data. + */ + String getSummary(); + + /** + * Load connection data from a settings store. + * @param store the settings store to access. + */ + void load(ISettingsStore store); + + /** + * Store connection data into a settings store. + * @param store the settings store to access. + */ + void save(ISettingsStore store); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/KeyboardInteractiveDialog.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/KeyboardInteractiveDialog.java new file mode 100644 index 00000000000..8e45799ff72 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/KeyboardInteractiveDialog.java @@ -0,0 +1,193 @@ +/******************************************************************************* + * Copyright (c) 2000, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Atsuhiko Yamanaka, JCraft,Inc. - initial API and implementation. + * IBM Corporation - ongoing maintenance + * Martin Oberhuber (Wind River) - copied and adapted from team.cvs.ui + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; + +/** + * A dialog for keyboad-interactive authentication for the ssh2 connection. + */ +public class KeyboardInteractiveDialog extends TrayDialog { + // widgets + private Text[] texts; + + protected String domain; + protected String destination; + protected String name; + protected String instruction; + protected String lang; + protected String[] prompt; + protected boolean[] echo; + private String message; + private String[] result; + + /** + * Creates a nwe KeyboardInteractiveDialog. + * + * @param parentShell the parent shell + * @param connectionId an id for the connection + * @param destination the location + * @param name the name + * @param instruction the instruction + * @param prompt the titles for textfields + * @param echo '*' should be used or not + */ + public KeyboardInteractiveDialog(Shell parentShell, + String connectionId, + String destination, + String name, + String instruction, + String[] prompt, + boolean[] echo){ + super(parentShell); + this.domain=connectionId; + this.destination=destination; + this.name=name; + this.instruction=instruction; + this.prompt=prompt; + this.echo=echo; + this.message=NLS.bind(SshMessages.KeyboardInteractiveDialog_message, new String[] { destination+(name!=null && name.length()>0 ? ": "+name : "") }); //NON-NLS-1$ //$NON-NLS-1$ //$NON-NLS-2$ + } + /** + * @see Window#configureShell + */ + @Override +protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(message); + } + /** + * @see Window#create + */ + @Override +public void create() { + super.create(); + if(texts.length>0){ + texts[0].setFocus(); + } + } + /** + * @see Dialog#createDialogArea + */ + @Override +protected Control createDialogArea(Composite parent) { + Composite main=new Composite(parent, SWT.NONE); + GridLayout layout=new GridLayout(); + layout.numColumns=3; + main.setLayout(layout); + main.setLayoutData(new GridData(GridData.FILL_BOTH)); + + // set F1 help + PlatformUI.getWorkbench().getHelpSystem().setHelp(main, ISshConstants.HELP_KEYBOARD_INTERACTIVE_DIALOG); + + if (message!=null) { + Label messageLabel=new Label(main, SWT.WRAP); + messageLabel.setText(message); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan=3; + messageLabel.setLayoutData(data); + } + if(domain!=null){ + Label label = new Label(main, SWT.WRAP); + label.setText(NLS.bind(SshMessages.KeyboardInteractiveDialog_labelConnection, new String[] { domain })); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan=3; + label.setLayoutData(data); + } + if (instruction!=null && instruction.length()>0) { + Label messageLabel=new Label(main, SWT.WRAP); + messageLabel.setText(instruction); + GridData data=new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan=3; + messageLabel.setLayoutData(data); + } + createPasswordFields(main); + return main; + } + /** + * Creates the widgets that represent the entry area. + * + * @param parent the parent of the widgets + */ + @SuppressWarnings("unused") +protected void createPasswordFields(Composite parent) { + texts=new Text[prompt.length]; + + for(int i=0; i + * The default implementation of this framework method sets + * this dialog's return code to Window.OK + * and closes the dialog. Subclasses may override. + *

+ */ + @Override +protected void okPressed() { + result=new String[prompt.length]; + for(int i=0; i + * The default implementation of this framework method sets + * this dialog's return code to Window.CANCEL + * and closes the dialog. Subclasses may override. + *

+ */ + @Override +protected void cancelPressed() { + result=null; + super.cancelPressed(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshConnection.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshConnection.java new file mode 100644 index 00000000000..954b76aa4ba --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshConnection.java @@ -0,0 +1,373 @@ +/******************************************************************************* + * Copyright (c) 2006, 2015 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [175686] Adapted to new IJSchService API + * - copied code from org.eclipse.team.cvs.ssh2/JSchSession (Copyright IBM) + * Martin Oberhuber (Wind River) - [198790] make SSH createSession() protected + * Mikhail Kalugin - [201864] Fix Terminal SSH keyboard interactive authentication + * Martin Oberhuber (Wind River) - [155026] Add keepalives for SSH connection + * Johnson Ma (Wind River) - [218880] Add UI setting for ssh keepalives + * Martin Oberhuber (Wind River) - [225792] Rename SshConnector.getTelnetSettings() to getSshSettings() + * Martin Oberhuber (Wind River) - [168197] Replace JFace MessagDialog by SWT MessageBox + * Martin Oberhuber (Wind River) - [205674][ssh] Terminal remains "connecting" when authentication is cancelled + * Michael Scharf (Wind River) - 240420: [terminal][ssh]Channel is not closed when the connection is closed with the close button + * Martin Oberhuber (Wind River) - [206919] Improve SSH Terminal Error Reporting + * Andrei Sobolev (Xored) - [250456] Ssh banner message causes IllegalArgumentException popup + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; + +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.NullProgressMonitor; +import org.eclipse.core.runtime.OperationCanceledException; +import org.eclipse.jface.window.Window; +import org.eclipse.jsch.core.IJSchService; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.connector.ssh.activator.UIPlugin; + +import com.jcraft.jsch.ChannelShell; +import com.jcraft.jsch.JSchException; +import com.jcraft.jsch.Session; +import com.jcraft.jsch.UIKeyboardInteractive; +import com.jcraft.jsch.UserInfo; + +public class SshConnection extends Thread { + private static int fgNo; + /* default */ final ITerminalControl fControl; + private final SshConnector fConn; + private Session fSession; + private boolean fDisconnectHasBeenCalled; + protected SshConnection(SshConnector conn,ITerminalControl control) { + super("SshConnection-"+fgNo++); //$NON-NLS-1$ + fControl = control; + fConn = conn; + fControl.setState(TerminalState.CONNECTING); + } + + //---------------------------------------------------------------------- + // + //---------------------------------------------------------------------- + + /** + * Create a Jsch session. + * Subclasses can override in order to replace the UserInfo wrapper + * (for non-interactive usage, for instance), or in order to change + * the Jsch config (for instance, in order to switch off strict + * host key checking or in order to add specific ciphers). + */ + protected Session createSession(String username, String password, String hostname, int port, UserInfo wrapperUI, IProgressMonitor monitor) throws JSchException { + IJSchService service = UIPlugin.getDefault().getJSchService(); + if (service == null) + return null; + Session session = service.createSession(hostname, port, username); + //session.setTimeout(getSshTimeoutInMillis()); + session.setTimeout(0); //never time out on the session + session.setServerAliveCountMax(6); //give up after 6 tries (remote will be dead after 30 min) + if (password != null) + session.setPassword(password); + session.setUserInfo(wrapperUI); + return session; + } + + public static void shutdown() { + //TODO: Store all Jsch sessions in a pool and disconnect them on shutdown + } + + //---------------------------------------------------------------------- + // + //---------------------------------------------------------------------- + + @Override + public void run() { + boolean connectSucceeded = false; + String host = ""; //$NON-NLS-1$ + int port = ISshSettings.DEFAULT_SSH_PORT; + try { + int nTimeout = fConn.getSshSettings().getTimeout() * 1000; + int nKeepalive = fConn.getSshSettings().getKeepalive() * 1000; + host = fConn.getSshSettings().getHost(); + String user = fConn.getSshSettings().getUser(); + String password = fConn.getSshSettings().getPassword(); + port = fConn.getSshSettings().getPort(); + + UserInfo ui=new MyUserInfo(null, user, password); + + Session session = createSession(user, password, host, port, + ui, new NullProgressMonitor()); + synchronized (this) { + fSession = session; + } + + //java.util.Hashtable config=new java.util.Hashtable(); + //config.put("StrictHostKeyChecking", "no"); + //session.setConfig(config); + //ui.aboutToConnect(); + if (nKeepalive > 0) { + session.setServerAliveInterval(nKeepalive); //default is 5 minutes + } + // dont try to connect if disconnect has been requested already + synchronized (this) { + if (fDisconnectHasBeenCalled) + return; + } + + session.connect(nTimeout); // making connection with timeout. + // if we got disconnected, do not continue + if(!isSessionConnected()) + return; + ChannelShell channel=(ChannelShell) session.openChannel("shell"); //$NON-NLS-1$ + channel.setPtyType("xterm"); //$NON-NLS-1$ + // TERM=xterm implies VT100 line wrapping mode + fControl.setVT100LineWrapping(true); + channel.connect(); + + // maybe the terminal was disconnected while we were connecting + if (isSessionConnected() && channel.isConnected()) { + connectSucceeded = true; + fConn.setInputStream(channel.getInputStream()); + fConn.setOutputStream(channel.getOutputStream()); + fConn.setChannel(channel); + fControl.setState(TerminalState.CONNECTED); + try { + // read data until the connection gets terminated + readDataForever(fConn.getInputStream()); + } catch (InterruptedIOException e) { + // we got interrupted: we are done... + } + } + } catch (Exception e) { + Throwable cause = e; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + String origMsg = cause.getMessage(); + String msg = SshMessages.getMessageFor(cause); + if ((cause instanceof JSchException) && origMsg != null && origMsg.startsWith("Auth")) { //$NON-NLS-1$ + if (origMsg.indexOf("cancel") >= 0) { //$NON-NLS-1$ + msg = SshMessages.SSH_AUTH_CANCEL; + } else if (origMsg.indexOf("fail") >= 0) { //$NON-NLS-1$ + msg = SshMessages.SSH_AUTH_FAIL; + } + } + if (!connectSucceeded) { + String hostPort = host; + if (port != ISshSettings.DEFAULT_SSH_PORT) { + hostPort = hostPort + ':' + port; + } + msg = NLS.bind(SshMessages.ERROR_CONNECTING, hostPort, msg); + } + connectFailed(msg, msg); + } finally { + // make sure the terminal is disconnected when the thread ends + try { + disconnect(); + } finally { + // when reading is done, we set the state to closed + fControl.setState(TerminalState.CLOSED); + } + } + } + + /* default */ synchronized boolean isSessionConnected() { + return !fDisconnectHasBeenCalled && fSession != null && fSession.isConnected(); + } + + /** + * disconnect the ssh session + */ + void disconnect() { + interrupt(); + synchronized (this) { + fDisconnectHasBeenCalled=true; + if(fSession!=null) { + try { + fSession.disconnect(); + } catch (Exception e) { + // Ignore NPE due to bug in JSch if disconnecting + // while not yet authenticated + } + fSession=null; + } + } + } + /** + * Read the data from the ssh connection and display it in the terminal. + * @param in + * @throws IOException + */ + private void readDataForever(InputStream in) throws IOException { + // read the data + byte bytes[]=new byte[32*1024]; + int n; + // read until the thread gets interrupted.... + while( (n=in.read(bytes))!=-1) { + fControl.getRemoteToTerminalOutputStream().write(bytes,0,n); + } + } + + protected static Display getStandardDisplay() { + Display display = Display.getCurrent(); + if( display==null ) { + display = Display.getDefault(); + } + return display; + } + + private class MyUserInfo implements UserInfo, UIKeyboardInteractive { + /* default */ final String fConnectionId; + /* default */ final String fUser; + private String fPassword; + private String fPassphrase; + private int fAttemptCount; + + public MyUserInfo(String connectionId, String user, String password) { + fConnectionId = connectionId; + fUser = user; + fPassword = password; + } + @Override + public String getPassword() { + return fPassword; + } + @Override + public boolean promptYesNo(final String str) { + //need to switch to UI thread for prompting + final boolean[] retval = new boolean[1]; + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + // [168197] Replace JFace MessagDialog by SWT MessageBox + //retval[0] = MessageDialog.openQuestion(null, SshMessages.WARNING, str); + if (isSessionConnected()) { + MessageBox mb = new MessageBox(fControl.getShell(), SWT.ICON_QUESTION | SWT.YES | SWT.NO); + mb.setText(SshMessages.WARNING); + mb.setMessage(str); + retval[0] = (mb.open() == SWT.YES); + } else { + retval[0] = false; + } + } + }); + return retval[0]; + } + private String promptSecret(final String message) { + final String[] retval = new String[1]; + getStandardDisplay().syncExec(new Runnable() { + @Override + public void run() { + if (isSessionConnected()) { + UserValidationDialog uvd = new UserValidationDialog(null, fConnectionId, fUser, message); + uvd.setUsernameMutable(false); + if (uvd.open() == Window.OK) { + retval[0] = uvd.getPassword(); + } else { + retval[0] = null; + } + } else { + retval[0] = null; + } + } + }); + return retval[0]; + } + @Override + public String getPassphrase() { + return fPassphrase; + } + @Override + public boolean promptPassphrase(String message) { + fPassphrase = promptSecret(message); + return (fPassphrase!=null); + } + @Override + public boolean promptPassword(final String message) { + String _password = promptSecret(message); + if (_password!=null) { + fPassword=_password; + return true; + } + return false; + } + @Override + public void showMessage(final String message) { + Display.getDefault().syncExec(new Runnable() { + @Override + public void run() { + // [168197] Replace JFace MessagDialog by SWT MessageBox + // MessageDialog.openInformation(null, SshMessages.INFO, message); + if (isSessionConnected()) { + MessageBox mb = new MessageBox(fControl.getShell(), SWT.ICON_INFORMATION | SWT.OK); + mb.setText(SshMessages.INFO); + mb.setMessage(message); + mb.open(); + } + } + }); + } + @Override + public String[] promptKeyboardInteractive(final String destination, + final String name, final String instruction, + final String[] prompt, final boolean[] echo) + { + if (prompt.length == 0) { + // No need to prompt, just return an empty String array + return new String[0]; + } + try{ + if (fAttemptCount == 0 && fPassword != null && prompt.length == 1 && prompt[0].trim().equalsIgnoreCase("password:")) { //$NON-NLS-1$ + // Return the provided password the first time but always prompt on subsequent tries + fAttemptCount++; + return new String[] { fPassword }; + } + final String[][] finResult = new String[1][]; + getStandardDisplay().syncExec(new Runnable() { + @Override + public void run() { + if (isSessionConnected()) { + KeyboardInteractiveDialog dialog = new KeyboardInteractiveDialog(null, fConnectionId, destination, name, instruction, prompt, echo); + dialog.open(); + finResult[0] = dialog.getResult(); + } else { + finResult[0] = null; // indicate cancel to JSch + } + } + }); + String[] result=finResult[0]; + if (result == null) + return null; // cancelled + if (result.length == 1 && prompt.length == 1 && prompt[0].trim().equalsIgnoreCase("password:")) { //$NON-NLS-1$ + fPassword = result[0]; + } + fAttemptCount++; + return result; + } + catch(OperationCanceledException e){ + return null; + } + } + } + + private void connectFailed(String terminalText, String msg) { + Logger.log(terminalText); + fControl.displayTextInTerminal(terminalText); + // fControl.setMsg(msg); + } + +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshConnector.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshConnector.java new file mode 100644 index 00000000000..e940feafdb3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshConnector.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [225792] Rename SshConnector.getTelnetSettings() to getSshSettings() + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +import com.jcraft.jsch.ChannelShell; +import com.jcraft.jsch.JSch; + +public class SshConnector extends TerminalConnectorImpl { + private OutputStream fOutputStream; + private InputStream fInputStream; + private JSch fJsch; + private ChannelShell fChannel; + private SshConnection fConnection; + private final SshSettings fSettings; + private int fWidth; + private int fHeight; + public SshConnector() { + this(new SshSettings()); + } + public SshConnector(SshSettings settings) { + fSettings=settings; + } + @Override + public void initialize() throws Exception { + fJsch=new JSch(); + } + @Override + public void connect(ITerminalControl control) { + super.connect(control); + fConnection = new SshConnection(this,control); + fConnection.start(); + } + @Override + synchronized public void doDisconnect() { + fConnection.disconnect(); + if (getInputStream() != null) { + try { + getInputStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + + if (getTerminalToRemoteStream() != null) { + try { + getTerminalToRemoteStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + } + @Override + public void setTerminalSize(int newWidth, int newHeight) { + if(fChannel!=null && (newWidth!=fWidth || newHeight!=fHeight)) { + //avoid excessive communications due to change size requests by caching previous size + fChannel.setPtySize(newWidth, newHeight, 8*newWidth, 8*newHeight); + fWidth=newWidth; + fHeight=newHeight; + } + } + public InputStream getInputStream() { + return fInputStream; + } + @Override + public OutputStream getTerminalToRemoteStream() { + return fOutputStream; + } + void setInputStream(InputStream inputStream) { + fInputStream = inputStream; + } + void setOutputStream(OutputStream outputStream) { + fOutputStream = outputStream; + } + /** + * Return the SSH Settings. + * + * @return the settings for a concrete connection. + * @since org.eclipse.tm.terminal.ssh 2.0 renamed from getTelnetSettings() + */ + public ISshSettings getSshSettings() { + return fSettings; + } + @Override + public void setDefaultSettings() { + fSettings.load(new NullSettingsStore()); + } + @Override + public String getSettingsSummary() { + return fSettings.getSummary(); + } + @Override + public void load(ISettingsStore store) { + fSettings.load(store); + } + @Override + public void save(ISettingsStore store) { + fSettings.save(store); + } + protected JSch getJsch() { + return fJsch; + } + ChannelShell getChannel() { + return fChannel; + } + void setChannel(ChannelShell channel) { + fChannel = channel; + fWidth=-1; + fHeight=-1; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshMessages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshMessages.java new file mode 100644 index 00000000000..74f0334e6e8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshMessages.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2000, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Johnson Ma (Wind River) - [218880] Add UI setting for ssh keepalives + * Martin Oberhuber (Wind River) - [206919] Improve SSH Terminal Error Reporting (Adopting code from org.eclipse.team.cvs.core) + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import java.lang.reflect.Field; + +import org.eclipse.osgi.util.NLS; + +public class SshMessages extends NLS { + static { + NLS.initializeMessages(SshMessages.class.getName(), SshMessages.class); + } + public static String USER; + public static String HOST; + public static String PORT; + public static String PASSWORD; + public static String TIMEOUT; + public static String KEEPALIVE; + public static String KEEPALIVE_Tooltip; + public static String WARNING; + public static String INFO; + + //These are from org.eclipse.team.cvs.ui.CVSUIMessages + public static String UserValidationDialog_required; + public static String UserValidationDialog_labelUser; + public static String UserValidationDialog_labelPassword; + public static String UserValidationDialog_password; + public static String UserValidationDialog_user; + public static String UserValidationDialog_5; + public static String UserValidationDialog_6; + public static String UserValidationDialog_7; + + public static String KeyboardInteractiveDialog_message; + public static String KeyboardInteractiveDialog_labelConnection; + + public static String ERROR_CONNECTING; + public static String TerminalCommunicationException_io; + public static String SSH_AUTH_CANCEL; + public static String SSH_AUTH_FAIL; + public static String com_jcraft_jsch_JSchException; + public static String java_io_IOException; + public static String java_io_EOFException; + public static String java_io_InterruptedIOException; + public static String java_net_UnknownHostException; + public static String java_net_ConnectException; + public static String java_net_SocketException; + public static String java_net_NoRouteToHostException; + + // + + public static String getMessageFor(Throwable throwable) { + String message = getMessage(getMessageKey(throwable)); + if (message == null) { + message = NLS.bind(SshMessages.TerminalCommunicationException_io, (new Object[] { throwable.toString() })); + } else { + message = NLS.bind(message, (new Object[] { throwable.getMessage() })); + } + return message; + } + + private static String getMessageKey(Throwable t) { + String name = t.getClass().getName(); + name = name.replace('.', '_'); + return name; + } + + // + // + + public static String getMessage(String key) { + try { + Field f = SshMessages.class.getDeclaredField(key); + Object o = f.get(null); + if (o instanceof String) + return (String) o; + } catch (SecurityException e) { + } catch (NoSuchFieldException e) { + } catch (IllegalArgumentException e) { + } catch (IllegalAccessException e) { + } + return null; + } + + // + + } diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshMessages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshMessages.properties new file mode 100644 index 00000000000..70588e272be --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshMessages.properties @@ -0,0 +1,55 @@ +############################################################################### +# Copyright (c) 2000, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +# Martin Oberhuber (Wind River) - fixed copyright headers and beautified +# Johnson Ma (Wind River) - [218880] Add UI setting for ssh keepalives +# Martin Oberhuber (Wind River) - [206919] Improve SSH Terminal Error Reporting (Adopting code from org.eclipse.team.cvs.core) +############################################################################### + +# NLS_MESSAGEFORMAT_VAR + +HOST = Host +USER = User +PORT = Port +PASSWORD = Password +TIMEOUT = Timeout (sec) +KEEPALIVE = KeepAlive (sec) +KEEPALIVE_Tooltip=Interval for sending keepalive messages in case of inactivity. Enter 0 to disable keepalives. +WARNING = Warning +INFO = Info + +#These are from cvs.ui/messages.properties +UserValidationDialog_required=Password Required +UserValidationDialog_labelUser={0} +UserValidationDialog_labelPassword={1} +UserValidationDialog_password=&Password: +UserValidationDialog_user=&User name: +UserValidationDialog_5=Connection: +UserValidationDialog_6=&Save password +UserValidationDialog_7=Saved passwords are stored on your computer in a file that is difficult, but not impossible, for an intruder to read. + +KeyboardInteractiveDialog_message=Keyboard Interactive authentication for {0} +KeyboardInteractiveDialog_labelConnection=Enter values for the following connection: {0} + +# from org.eclipse.team.cvs.core/messages.properties (c) IBM 2000, 2007 +ERROR_CONNECTING=Error connecting {0} : {1} +TerminalCommunicationException_io=Communication error: {0} +SSH_AUTH_CANCEL=SSH Authentication cancelled. +SSH_AUTH_FAIL=SSH Authentication failed. +com_jcraft_jsch_JSchException=SSH client error: {0} +java_io_IOException=I/O exception occurred: {0} +java_io_EOFException=End of file encountered: {0} +java_io_InterruptedIOException=I/O has been interrupted. +java_net_UnknownHostException=Cannot locate host: {0} +java_net_ConnectException=Cannot connect to host: {0} +java_net_SocketException=Socket Exception: {0} +java_net_NoRouteToHostException={0} +# from org.eclipse.team.cvs.core diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshSettings.java new file mode 100644 index 00000000000..f39e8c6460f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshSettings.java @@ -0,0 +1,137 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Mikhail Kalugin - [201867] Improve Terminal SSH connection summary string + * Johnson Ma (Wind River) - [218880] Add UI setting for ssh keepalives + * Bryan Hunt - [313991] cannot programatically pass password to SshConnector + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +public class SshSettings implements ISshSettings { + protected String fHost; + protected String fUser; + protected String fPassword; + protected String fPort; + protected String fTimeout; + protected String fKeepalive; + @Override + public String getHost() { + return fHost; + } + + public void setHost(String strHost) { + fHost = strHost; + } + + @Override + public String getSummary() { + String settings = getUser()+'@'+getHost(); + if(getPort()!=ISshSettings.DEFAULT_SSH_PORT) { + settings += ":" + getPort(); //$NON-NLS-1$ + } + return settings; + } + + @Override + public void load(ISettingsStore store) { + fHost = store.get("Host", "");//$NON-NLS-1$ //$NON-NLS-2$ + fUser = store.get("User", "");//$NON-NLS-1$ //$NON-NLS-2$ + // ISettingsStore providers have to make sure that + // the password is not saved in some as plain text + // on disk. [bug 313991] + fPassword = store.get("Password", "");//$NON-NLS-1$ //$NON-NLS-2$ + fPort = store.get("Port", String.valueOf(ISshSettings.DEFAULT_SSH_PORT));//$NON-NLS-1$ + fTimeout = store.get("Timeout", "0");//$NON-NLS-1$ //$NON-NLS-2$ + fKeepalive = store.get("Keepalive", "300");//$NON-NLS-1$ //$NON-NLS-2$ + } + + @Override + public void save(ISettingsStore store) { + store.put("Host", fHost);//$NON-NLS-1$ + store.put("User", fUser);//$NON-NLS-1$ + store.put("Port", fPort);//$NON-NLS-1$ + // We do *not* store the password in the settings because + // this can cause the password to be stored as plain text + // in some settings file + store.put("Timeout", fTimeout);//$NON-NLS-1$ + store.put("Keepalive", fKeepalive);//$NON-NLS-1$ + } + + + @Override + 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; + } + + @Override + public int getKeepalive() { + try { + return Integer.parseInt(fKeepalive); + } catch (NumberFormatException numberFormatException) { + return 300; + } + } + public String getKeepaliveString() { + return fKeepalive; + } + + public void setKeepalive(String keepalive) { + fKeepalive = keepalive; + } + + @Override + public String getUser() { + return fUser; + } + + public void setUser(String user) { + fUser = user; + } + @Override + public int getPort() { + try { + return Integer.parseInt(fPort); + } catch (NumberFormatException numberFormatException) { + return ISshSettings.DEFAULT_SSH_PORT; + } + } + + public String getPortString() { + return fPort; + } + + public void setPort(String port) { + fPort = port; + } + + @Override + public String getPassword() { + return fPassword; + } + + public void setPassword(String password) { + fPassword = password; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshSettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshSettingsPage.java new file mode 100644 index 00000000000..02b9428e9a8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/SshSettingsPage.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Johnson Ma (Wind River) - [218880] Add UI setting for ssh keepalives + * Martin Oberhuber (Wind River) - [206917] Add validation for Terminal Settings + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; + +public class SshSettingsPage extends AbstractSettingsPage { + private Text fHostText; + private Text fUser; + private Text fTimeout; + private Text fKeepalive; + private final SshSettings fTerminalSettings; + private Text fPort; + private Text fPassword; + + public SshSettingsPage(SshSettings settings) { + fTerminalSettings=settings; + } + @Override + public void saveSettings() { + fTerminalSettings.setHost(fHostText.getText()); + fTerminalSettings.setUser(fUser.getText()); + fTerminalSettings.setPassword(fPassword.getText()); + fTerminalSettings.setPort(fPort.getText()); + fTerminalSettings.setTimeout(fTimeout.getText()); + fTerminalSettings.setKeepalive(fKeepalive.getText()); + } + + @Override + public void loadSettings() { + if(fTerminalSettings!=null) { + fHostText.setText(get(fTerminalSettings.getHost(),""));//$NON-NLS-1$ + fTimeout.setText(get(fTerminalSettings.getTimeoutString(),"0"));//$NON-NLS-1$ + fKeepalive.setText(get(fTerminalSettings.getKeepaliveString(),"300"));//$NON-NLS-1$ + fUser.setText(get(fTerminalSettings.getUser(),""));//$NON-NLS-1$ + fPort.setText(get(fTerminalSettings.getPortString(), String.valueOf(ISshSettings.DEFAULT_SSH_PORT))); + fPassword.setText(get(fTerminalSettings.getPassword(),""));//$NON-NLS-1$ + } + } + String get(String value, String def) { + if(value==null || value.length()==0) + return def; + return value; + } + @Override + public boolean validateSettings() { + String message = null; + int messageType = IMessageProvider.NONE; + boolean valid = true; + + if (fHostText.getText().trim().length() == 0) { + String m = "Please enter a host IP or name."; //$NON-NLS-1$ + int mt = IMessageProvider.INFORMATION; + updateControlDecoration(fHostText, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fHostText, null, IMessageProvider.NONE); + } + if (fUser.getText().trim().length() == 0) { + String m = "Please enter a username."; //$NON-NLS-1$ + int mt = IMessageProvider.INFORMATION; + updateControlDecoration(fUser, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fUser, null, IMessageProvider.NONE); + } + try { + int p = Integer.parseInt(fPort.getText().trim()); + if (p <= 0 || p > 65535) { + String m = "Invalid network port. Must be between 0 and 65535."; //$NON-NLS-1$ + int mt = IMessageProvider.ERROR; + updateControlDecoration(fPort, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fPort, null, IMessageProvider.NONE); + } + p = Integer.parseInt(fTimeout.getText().trim()); + if (p < 0) { + String m = "Invalid timeout. Must be greater than 0."; //$NON-NLS-1$ + int mt = IMessageProvider.ERROR; + updateControlDecoration(fTimeout, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fTimeout, null, IMessageProvider.NONE); + } + p = Integer.parseInt(fKeepalive.getText().trim()); + if (p < 0) { + String m = "Invalid keep alive. Must be greater than 0."; //$NON-NLS-1$ + int mt = IMessageProvider.ERROR; + updateControlDecoration(fKeepalive, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fKeepalive, null, IMessageProvider.NONE); + } + } catch (Exception e) { + valid = false; + } + + setMessage(message, messageType); + return valid; + } + @Override + 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); + gridData.horizontalIndent = FieldDecorationRegistry.getDefault().getMaximumDecorationWidth(); + + composite.setLayout(gridLayout); + composite.setLayoutData(gridData); + + fHostText = createTextField(composite, SshMessages.HOST); + fUser = createTextField(composite, SshMessages.USER); + fPassword = createTextField(composite, SshMessages.PASSWORD,SWT.PASSWORD); + fTimeout = createTextField(composite, SshMessages.TIMEOUT); + fKeepalive = createTextField(composite, SshMessages.KEEPALIVE); + fKeepalive.setToolTipText(SshMessages.KEEPALIVE_Tooltip); + fPort = createTextField(composite, SshMessages.PORT); + loadSettings(); + } + private Text createTextField(Composite composite, String labelTxt, int textOptions) { + GridData gridData; + // Add label + Label ctlLabel = new Label(composite, SWT.RIGHT); + ctlLabel.setText(labelTxt + ":"); //$NON-NLS-1$ + + // Add control + gridData = new GridData(GridData.FILL_HORIZONTAL); + final Text text= new Text(composite, SWT.BORDER | textOptions); + text.setLayoutData(gridData); + text.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + fireListeners(text); + } + }); + createControlDecoration(text); + return text; + } + private Text createTextField(Composite composite, String labelTxt) { + return createTextField(composite, labelTxt, 0); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/UserValidationDialog.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/UserValidationDialog.java new file mode 100644 index 00000000000..ba862db7d15 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/connector/UserValidationDialog.java @@ -0,0 +1,285 @@ +/******************************************************************************* + * Copyright (c) 2000, 2018 IBM Corporation and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * IBM Corporation - initial API and implementation + * Martin Oberhuber (Wind River) - copied from org.eclipse.team.cvs.ui + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.connector; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.window.Window; +import org.eclipse.osgi.util.NLS; +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.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.PlatformUI; + +/** + * A dialog for prompting for a username and password + */ +public class UserValidationDialog extends TrayDialog { + // widgets + protected Text usernameField; + protected Text passwordField; + protected Button allowCachingButton; + + protected String domain; + protected String defaultUsername; + protected String password = null; + protected boolean allowCaching = false; + protected Image keyLockImage; + + // whether or not the username can be changed + protected boolean isUsernameMutable = true; + protected String username = null; + protected String message = null; + + /** + * Creates a new UserValidationDialog. + * + * @param parentShell the parent shell + * @param location the location + * @param defaultName the default user name + * @param message a mesage to display to the user + */ + public UserValidationDialog(Shell parentShell, String location, String defaultName, String message) { + super(parentShell); + setShellStyle(getShellStyle() | SWT.RESIZE); + this.defaultUsername = defaultName; + this.domain = location; + this.message = message; + } + /** + * @see Window#configureShell + */ + @Override + protected void configureShell(Shell newShell) { + super.configureShell(newShell); + newShell.setText(SshMessages.UserValidationDialog_required); + // set F1 help + PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell, ISshConstants.HELP_USER_VALIDATION_DIALOG); + } + /** + * @see Window#create + */ + @Override + public void create() { + super.create(); + // add some default values + usernameField.setText(defaultUsername); + + if (isUsernameMutable) { + // give focus to username field + usernameField.selectAll(); + usernameField.setFocus(); + } else { + usernameField.setEditable(false); + passwordField.setFocus(); + } + } + + /** + * @see Dialog#createDialogArea + */ + @Override + protected Control createDialogArea(Composite parent) { + Composite top = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + + top.setLayout(layout); + top.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + Composite imageComposite = new Composite(top, SWT.NONE); + layout = new GridLayout(); + imageComposite.setLayout(layout); + imageComposite.setLayoutData(new GridData(GridData.FILL_VERTICAL)); + + Composite main = new Composite(top, SWT.NONE); + layout = new GridLayout(); + layout.numColumns = 3; + main.setLayout(layout); + main.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + + Label imageLabel = new Label(imageComposite, SWT.NONE); + //keyLockImage = TeamImages.getImageDescriptor(ITeamUIImages.IMG_KEY_LOCK).createImage(); + //imageLabel.setImage(keyLockImage); + GridData data = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); + imageLabel.setLayoutData(data); + + if (message != null) { + Label messageLabel = new Label(main, SWT.WRAP); + messageLabel.setText(message); + data = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); + data.horizontalSpan = 3; + data.widthHint = 300; + messageLabel.setLayoutData(data); + } + if (domain != null) { + Label d = new Label(main, SWT.WRAP); + d.setText(SshMessages.UserValidationDialog_5); + data = new GridData(); + d.setLayoutData(data); + Label label = new Label(main, SWT.WRAP); + if (isUsernameMutable) { + label.setText(NLS.bind(SshMessages.UserValidationDialog_labelUser, new String[] { domain })); + } else { + label.setText(NLS.bind(SshMessages.UserValidationDialog_labelPassword, (new Object[]{defaultUsername, domain}))); + } + data = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); + data.horizontalSpan = 2; + data.widthHint = 300; + label.setLayoutData(data); + } + createUsernameFields(main); + createPasswordFields(main); + + if(domain != null) { + allowCachingButton = new Button(main, SWT.CHECK); + allowCachingButton.setText(SshMessages.UserValidationDialog_6); + data = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL); + data.horizontalSpan = 3; + allowCachingButton.setLayoutData(data); + allowCachingButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + allowCaching = allowCachingButton.getSelection(); + } + }); + Composite warningComposite = new Composite(main, SWT.NONE); + layout = new GridLayout(); + layout.numColumns = 2; + layout.marginHeight = 0; + layout.marginHeight = 0; + warningComposite.setLayout(layout); + data = new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan = 3; + warningComposite.setLayoutData(data); + Label warningLabel = new Label(warningComposite, SWT.NONE); + warningLabel.setImage(getImage(DLG_IMG_MESSAGE_WARNING)); + warningLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING | GridData.HORIZONTAL_ALIGN_BEGINNING)); + Label warningText = new Label(warningComposite, SWT.WRAP); + warningText.setText(SshMessages.UserValidationDialog_7); + data = new GridData(GridData.FILL_HORIZONTAL); + data.widthHint = 300; + warningText.setLayoutData(data); + } + + Dialog.applyDialogFont(parent); + + return main; + } + + /** + * Creates the three widgets that represent the password entry area. + * + * @param parent the parent of the widgets + */ + protected void createPasswordFields(Composite parent) { + new Label(parent, SWT.NONE).setText(SshMessages.UserValidationDialog_password); + + passwordField = new Text(parent, SWT.BORDER | SWT.PASSWORD); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan = 2; + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); + passwordField.setLayoutData(data); + } + /** + * Creates the three widgets that represent the user name entry area. + * + * @param parent the parent of the widgets + */ + protected void createUsernameFields(Composite parent) { + new Label(parent, SWT.NONE).setText(SshMessages.UserValidationDialog_user); + + usernameField = new Text(parent, SWT.BORDER); + GridData data = new GridData(GridData.FILL_HORIZONTAL); + data.horizontalSpan = 2; + data.widthHint = convertHorizontalDLUsToPixels(IDialogConstants.ENTRY_FIELD_WIDTH); + usernameField.setLayoutData(data); + } + + /** + * Returns the password entered by the user, or null + * if the user cancelled. + * + * @return the entered password + */ + public String getPassword() { + return password; + } + + /** + * Returns the username entered by the user, or null + * if the user cancelled. + * + * @return the entered username + */ + public String getUsername() { + return username; + } + + /** + * Returns true if the save password checkbox was selected. + * @return true if the save password checkbox was selected and false + * otherwise. + */ + public boolean getAllowCaching() { + return allowCaching; + } + + /** + * Notifies that the ok button of this dialog has been pressed. + *

+ * The default implementation of this framework method sets + * this dialog's return code to Window.OK + * and closes the dialog. Subclasses may override. + *

+ */ + @Override + protected void okPressed() { + password = passwordField.getText(); + username = usernameField.getText(); + + super.okPressed(); + } + /** + * Sets whether or not the username field should be mutable. + * This method must be called before create(), otherwise it + * will be ignored. + * + * @param value whether the username is mutable + */ + public void setUsernameMutable(boolean value) { + isUsernameMutable = value; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#close() + */ + @Override + public boolean close() { + if(keyLockImage != null) { + keyLockImage.dispose(); + } + return super.close(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/controls/SshWizardConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/controls/SshWizardConfigurationPanel.java new file mode 100644 index 00000000000..779b4c718d0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/controls/SshWizardConfigurationPanel.java @@ -0,0 +1,424 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361352] [TERMINALS][SSH] Add SSH terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.controls; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.equinox.security.storage.ISecurePreferences; +import org.eclipse.equinox.security.storage.SecurePreferencesFactory; +import org.eclipse.equinox.security.storage.StorageException; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage; +import org.eclipse.tm.terminal.connector.ssh.connector.SshConnector; +import org.eclipse.tm.terminal.connector.ssh.connector.SshSettings; +import org.eclipse.tm.terminal.connector.ssh.connector.SshSettingsPage; +import org.eclipse.tm.terminal.connector.ssh.nls.Messages; +import org.eclipse.tm.terminal.view.core.TerminalContextPropertiesProviderFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalContextPropertiesProvider; +import org.eclipse.tm.terminal.view.core.interfaces.constants.IContextPropertiesConstants; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; + +/** + * SSH wizard configuration panel implementation. + */ +public class SshWizardConfigurationPanel extends AbstractExtendedConfigurationPanel { + + private static final String SAVE_USER = "saveUser"; //$NON-NLS-1$ + private static final String SAVE_PASSWORD = "savePassword"; //$NON-NLS-1$ + + private SshSettings sshSettings; + private ISettingsPage sshSettingsPage; + private Button userButton; + private Button passwordButton; + + /** + * Constructor. + * + * @param container The configuration panel container or null. + */ + public SshWizardConfigurationPanel(IConfigurationPanelContainer container) { + super(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupPanel(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + panel.setLayoutData(data); + + // Create the host selection combo + if (isWithoutSelection()) createHostsUI(panel, true); + + SshConnector conn = new SshConnector(); + sshSettings = (SshSettings) conn.getSshSettings(); + sshSettings.setHost(getSelectionHost()); + sshSettings.setUser(getDefaultUser()); + + sshSettingsPage = new SshSettingsPage(sshSettings); + if (sshSettingsPage instanceof AbstractSettingsPage) { + ((AbstractSettingsPage)sshSettingsPage).setHasControlDecoration(true); + } + sshSettingsPage.createControl(panel); + + // Add the listener to the settings page + sshSettingsPage.addListener(new ISettingsPage.Listener() { + @Override + public void onSettingsPageChanged(Control control) { + if (getContainer() != null) getContainer().validate(); + } + }); + + // Create the encoding selection combo + createEncodingUI(panel, true); + + // if user and password for host should be saved or not + createSaveButtonsUI(panel, true); + + setControl(panel); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#setupData(java.util.Map) + */ + @Override + public void setupData(Map data) { + if (data == null || sshSettings == null || sshSettingsPage == null) return; + + String value = (String)data.get(ITerminalsConnectorConstants.PROP_IP_HOST); + if (value != null) sshSettings.setHost(value); + + Object v = data.get(ITerminalsConnectorConstants.PROP_IP_PORT); + value = v != null ? v.toString() : null; + if (value != null) sshSettings.setPort(value); + + v = data.get(ITerminalsConnectorConstants.PROP_TIMEOUT); + value = v != null ? v.toString() : null; + if (value != null) sshSettings.setTimeout(value); + + v = data.get(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE); + value = v != null ? v.toString() : null; + if (value != null) sshSettings.setKeepalive(value); + + value = (String)data.get(ITerminalsConnectorConstants.PROP_SSH_PASSWORD); + if (value != null) sshSettings.setPassword(value); + + value = (String)data.get(ITerminalsConnectorConstants.PROP_SSH_USER); + if (value != null) sshSettings.setUser(value); + + value = (String)data.get(ITerminalsConnectorConstants.PROP_ENCODING); + if (value != null) setEncoding(value); + + sshSettingsPage.loadSettings(); + } + + /** + * Returns the default user name. + * + * @return The default user name. + */ + private String getDefaultUser() { + ISelection selection = getSelection(); + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + ITerminalContextPropertiesProvider provider = TerminalContextPropertiesProviderFactory.getProvider(element); + if (provider != null) { + Object user = provider.getProperty(element, IContextPropertiesConstants.PROP_DEFAULT_USER); + if (user instanceof String) return ((String) user).trim(); + } + } + + return System.getProperty("user.name"); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#extractData(java.util.Map) + */ + @Override + public void extractData(Map data) { + if (data == null) return; + + // set the terminal connector id for ssh + data.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, "org.eclipse.tm.terminal.connector.ssh.SshConnector"); //$NON-NLS-1$ + + sshSettingsPage.saveSettings(); + data.put(ITerminalsConnectorConstants.PROP_IP_HOST,sshSettings.getHost()); + data.put(ITerminalsConnectorConstants.PROP_IP_PORT, Integer.valueOf(sshSettings.getPort())); + data.put(ITerminalsConnectorConstants.PROP_TIMEOUT, Integer.valueOf(sshSettings.getTimeout())); + data.put(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE, Integer.valueOf(sshSettings.getKeepalive())); + data.put(ITerminalsConnectorConstants.PROP_SSH_PASSWORD, sshSettings.getPassword()); + data.put(ITerminalsConnectorConstants.PROP_SSH_USER, sshSettings.getUser()); + data.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#fillSettingsForHost(java.lang.String) + */ + @Override + protected void fillSettingsForHost(String host) { + boolean saveUser = true; + boolean savePassword = false; + if (host != null && host.length() != 0){ + if (hostSettingsMap.containsKey(host)){ + Map hostSettings = hostSettingsMap.get(host); + if (hostSettings.get(ITerminalsConnectorConstants.PROP_IP_HOST) != null) { + sshSettings.setHost(hostSettings.get(ITerminalsConnectorConstants.PROP_IP_HOST)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_IP_PORT) != null) { + sshSettings.setPort(hostSettings.get(ITerminalsConnectorConstants.PROP_IP_PORT)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_TIMEOUT) != null) { + sshSettings.setTimeout(hostSettings.get(ITerminalsConnectorConstants.PROP_TIMEOUT)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE) != null) { + sshSettings.setKeepalive(hostSettings.get(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_SSH_USER) != null) { + sshSettings.setUser(hostSettings.get(ITerminalsConnectorConstants.PROP_SSH_USER)); + } + if (hostSettings.get(SAVE_PASSWORD) != null) { + savePassword = new Boolean(hostSettings.get(SAVE_PASSWORD)).booleanValue(); + } + if (!savePassword){ + sshSettings.setPassword(""); //$NON-NLS-1$ + } else { + String password = accessSecurePassword(sshSettings.getHost()); + if (password != null) { + sshSettings.setPassword(password); + } + } + + String encoding = hostSettings.get(ITerminalsConnectorConstants.PROP_ENCODING); + if (encoding == null || "null".equals(encoding)) { //$NON-NLS-1$ + String defaultEncoding = getSelectionEncoding(); + encoding = defaultEncoding != null && !"".equals(defaultEncoding.trim()) ? defaultEncoding.trim() : "ISO-8859-1"; //$NON-NLS-1$ //$NON-NLS-2$ + } + setEncoding(encoding); + } else { + sshSettings.setHost(getSelectionHost()); + sshSettings.setUser(getDefaultUser()); + saveUser = true; + savePassword = false; + } + // set settings in page + sshSettingsPage.loadSettings(); + userButton.setSelection(saveUser); + passwordButton.setSelection(savePassword); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel#doSaveWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + saveSettingsForHost(true); + super.doSaveWidgetValues(settings, idPrefix); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#saveSettingsForHost(boolean) + */ + @Override + protected void saveSettingsForHost(boolean add) { + boolean saveUser = userButton.getSelection(); + boolean savePassword = passwordButton.getSelection(); + String host = getHostFromSettings(); + if (host != null && host.length() != 0) { + if (hostSettingsMap.containsKey(host)){ + Map hostSettings = hostSettingsMap.get(host); + hostSettings.put(ITerminalsConnectorConstants.PROP_IP_HOST, sshSettings.getHost()); + hostSettings.put(ITerminalsConnectorConstants.PROP_IP_PORT, Integer.toString(sshSettings.getPort())); + hostSettings.put(ITerminalsConnectorConstants.PROP_TIMEOUT, Integer.toString(sshSettings.getTimeout())); + hostSettings.put(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE, Integer.toString(sshSettings.getKeepalive())); + if (saveUser) { + if (sshSettings.getUser() != null) { + hostSettings.put(ITerminalsConnectorConstants.PROP_SSH_USER, sshSettings.getUser()); + } else { + hostSettings.remove(ITerminalsConnectorConstants.PROP_SSH_USER); + } + } + else { + hostSettings.remove(ITerminalsConnectorConstants.PROP_SSH_USER); + } + + String encoding = getEncoding(); + if (encoding != null) { + String defaultEncoding = getSelectionEncoding(); + if (defaultEncoding != null && defaultEncoding.trim().equals(encoding)) { + encoding = null; + } + } + hostSettings.put(ITerminalsConnectorConstants.PROP_ENCODING, encoding); + hostSettings.put(SAVE_USER, Boolean.toString(saveUser)); + hostSettings.put(SAVE_PASSWORD, Boolean.toString(savePassword)); + + if (savePassword && sshSettings.getPassword() != null && sshSettings.getPassword().length() != 0){ + saveSecurePassword(host, sshSettings.getPassword()); + } + + // maybe unchecked the password button - so try to remove a saved password - if any + if (!savePassword) removeSecurePassword(host); + } else if (add) { + Map hostSettings = new HashMap(); + hostSettings.put(ITerminalsConnectorConstants.PROP_IP_HOST, sshSettings.getHost()); + hostSettings.put(ITerminalsConnectorConstants.PROP_IP_PORT, Integer.toString(sshSettings.getPort())); + hostSettings.put(ITerminalsConnectorConstants.PROP_TIMEOUT, Integer.toString(sshSettings.getTimeout())); + hostSettings.put(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE, Integer.toString(sshSettings.getKeepalive())); + if (saveUser) { + if (sshSettings.getUser() != null) { + hostSettings.put(ITerminalsConnectorConstants.PROP_SSH_USER, sshSettings.getUser()); + } + } + hostSettings.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + hostSettings.put(SAVE_USER, Boolean.toString(saveUser)); + hostSettings.put(SAVE_PASSWORD, Boolean.toString(savePassword)); + hostSettingsMap.put(host, hostSettings); + + if (savePassword && sshSettings.getPassword() != null && sshSettings.getPassword().length() != 0){ + saveSecurePassword(host, sshSettings.getPassword()); + } + } + } + } + + /** + * Save the password to the secure storage. + * + * @param host The host. Must not be null. + * @param password The password. Must not be null. + */ + private void saveSecurePassword(String host, String password) { + Assert.isNotNull(host); + Assert.isNotNull(password); + + // To access the secure storage, we need the preference instance + ISecurePreferences preferences = SecurePreferencesFactory.getDefault(); + if (preferences != null) { + // Construct the secure preferences node key + String nodeKey = "/Target Explorer SSH Password/" + host; //$NON-NLS-1$ + ISecurePreferences node = preferences.node(nodeKey); + if (node != null) { + try { + node.put("password", password, true); //$NON-NLS-1$ + } + catch (StorageException ex) { /* ignored on purpose */ } + } + } + } + + /** + * Reads the password from the secure storage. + * + * @param host The host. Must not be null. + * @return The password or null. + */ + private String accessSecurePassword(String host) { + Assert.isNotNull(host); + + // To access the secure storage, we need the preference instance + ISecurePreferences preferences = SecurePreferencesFactory.getDefault(); + if (preferences != null) { + // Construct the secure preferences node key + String nodeKey = "/Target Explorer SSH Password/" + host; //$NON-NLS-1$ + ISecurePreferences node = preferences.node(nodeKey); + if (node != null) { + String password = null; + try { + password = node.get("password", null); //$NON-NLS-1$ + } + catch (StorageException ex) { /* ignored on purpose */ } + + return password; + } + } + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#removeSecurePassword(java.lang.String) + */ + @Override + protected void removeSecurePassword(String host) { + Assert.isNotNull(host); + + // To access the secure storage, we need the preference instance + ISecurePreferences preferences = SecurePreferencesFactory.getDefault(); + if (preferences != null) { + // Construct the secure preferences node key + String nodeKey = "/Target Explorer SSH Password/" + host; //$NON-NLS-1$ + ISecurePreferences node = preferences.node(nodeKey); + if (node != null) { + node.remove("password"); //$NON-NLS-1$ + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#isValid() + */ + @Override + public boolean isValid(){ + return isEncodingValid() && sshSettingsPage.validateSettings(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#getHostFromSettings() + */ + @Override + protected String getHostFromSettings() { + sshSettingsPage.saveSettings(); + return sshSettings.getHost(); + } + + private void createSaveButtonsUI(final Composite parent, boolean separator) { + Assert.isNotNull(parent); + + if (separator) { + Label sep = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + } + + Composite panel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + userButton = new Button(panel, SWT.CHECK); + userButton.setLayoutData(new GridData(SWT.LEAD, SWT.CENTER, false, false)); + userButton.setText(Messages.SshWizardConfigurationPanel_saveUser); + + passwordButton = new Button(panel, SWT.CHECK); + passwordButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + passwordButton.setText(Messages.SshWizardConfigurationPanel_savePassword); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/launcher/SshLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/launcher/SshLauncherDelegate.java new file mode 100644 index 00000000000..9de83a43739 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/launcher/SshLauncherDelegate.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361352] [TERMINALS][SSH] Add SSH terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.launcher; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.connector.ssh.connector.ISshSettings; +import org.eclipse.tm.terminal.connector.ssh.connector.SshSettings; +import org.eclipse.tm.terminal.connector.ssh.controls.SshWizardConfigurationPanel; +import org.eclipse.tm.terminal.connector.ssh.nls.Messages; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +/** + * SSH launcher delegate implementation. + */ +@SuppressWarnings("restriction") +public class SshLauncherDelegate extends AbstractLauncherDelegate { + // The SSH terminal connection memento handler + private final IMementoHandler mementoHandler = new SshMementoHandler(); + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#needsUserConfiguration() + */ + @Override + public boolean needsUserConfiguration() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getPanel(org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer) + */ + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return new SshWizardConfigurationPanel(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#execute(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void execute(Map properties, ITerminalService.Done done) { + Assert.isNotNull(properties); + + // Set the terminal tab title + String terminalTitle = getTerminalTitle(properties); + if (terminalTitle != null) { + properties.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle); + } + + // For SSH terminals, force a new terminal tab each time it is launched, + // if not set otherwise from outside + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_FORCE_NEW)) { + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, Boolean.TRUE); + } + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + + /** + * Returns the terminal title string. + *

+ * The default implementation constructs a title like "SSH @ host (Start time) ". + * + * @return The terminal title string or null. + */ + private String getTerminalTitle(Map properties) { + // Try to see if the user set a title explicitly via the properties map. + String title = getDefaultTerminalTitle(properties); + if (title != null) return title; + + //No title,try to calculate the title + String host = (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST); + String user = (String)properties.get(ITerminalsConnectorConstants.PROP_SSH_USER); + Object value = properties.get(ITerminalsConnectorConstants.PROP_IP_PORT); + String port = value != null ? value.toString() : null; + + if (host != null && user!= null) { + DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + String date = format.format(new Date(System.currentTimeMillis())); + if (port != null && Integer.valueOf(port).intValue() != ISshSettings.DEFAULT_SSH_PORT) { + return NLS.bind(Messages.SshLauncherDelegate_terminalTitle_port, new String[]{user, host, port, date}); + } + return NLS.bind(Messages.SshLauncherDelegate_terminalTitle, new String[]{user, host, date}); + } + + return Messages.SshLauncherDelegate_terminalTitle_default; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) { + if (IMementoHandler.class.equals(adapter)) { + return mementoHandler; + } + return super.getAdapter(adapter); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#createTerminalConnector(java.util.Map) + */ + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String)properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) connectorId = "org.eclipse.tm.terminal.connector.ssh.SshConnector"; //$NON-NLS-1$ + + // Extract the ssh properties + String host = (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST); + Object value = properties.get(ITerminalsConnectorConstants.PROP_IP_PORT); + String port = value != null ? value.toString() : null; + value = properties.get(ITerminalsConnectorConstants.PROP_TIMEOUT); + String timeout = value != null ? value.toString() : null; + value = properties.get(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE); + String keepAlive = value != null ? value.toString() : null; + String password = (String)properties.get(ITerminalsConnectorConstants.PROP_SSH_PASSWORD); + String user = (String)properties.get(ITerminalsConnectorConstants.PROP_SSH_USER); + + int portOffset = 0; + if (properties.get(ITerminalsConnectorConstants.PROP_IP_PORT_OFFSET) instanceof Integer) { + portOffset = ((Integer)properties.get(ITerminalsConnectorConstants.PROP_IP_PORT_OFFSET)).intValue(); + if (portOffset < 0) portOffset = 0; + } + + // The real port to connect to is port + portOffset + if (port != null) { + port = Integer.toString(Integer.decode(port).intValue() + portOffset); + } + + // Construct the ssh settings store + ISettingsStore store = new SettingsStore(); + + // Construct the telnet settings + SshSettings sshSettings = new SshSettings(); + sshSettings.setHost(host); + sshSettings.setPort(port); + sshSettings.setTimeout(timeout); + sshSettings.setKeepalive(keepAlive); + sshSettings.setPassword(password); + sshSettings.setUser(user); + + // And save the settings to the store + sshSettings.save(store); + + // MWE TODO make sure this is NOT passed outside as this is plain text + store.put("Password", password); //$NON-NLS-1$ + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + return connector; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/launcher/SshMementoHandler.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/launcher/SshMementoHandler.java new file mode 100644 index 00000000000..76cf961d282 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/launcher/SshMementoHandler.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.launcher; + +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.equinox.security.storage.ISecurePreferences; +import org.eclipse.equinox.security.storage.SecurePreferencesFactory; +import org.eclipse.equinox.security.storage.StorageException; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.ui.IMemento; + +/** + * SSH terminal connection memento handler implementation. + */ +public class SshMementoHandler implements IMementoHandler { + + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#saveState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void saveState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + + // Do not write the terminal title to the memento -> needs to + // be recreated at the time of restoration. + memento.putString(ITerminalsConnectorConstants.PROP_IP_HOST, (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST)); + Object value = properties.get(ITerminalsConnectorConstants.PROP_IP_PORT); + memento.putInteger(ITerminalsConnectorConstants.PROP_IP_PORT, value instanceof Integer ? ((Integer)value).intValue() : -1); + value = properties.get(ITerminalsConnectorConstants.PROP_TIMEOUT); + memento.putInteger(ITerminalsConnectorConstants.PROP_TIMEOUT, value instanceof Integer ? ((Integer)value).intValue() : -1); + value = properties.get(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE); + memento.putInteger(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE, value instanceof Integer ? ((Integer)value).intValue() : -1); + memento.putString(ITerminalsConnectorConstants.PROP_SSH_USER, (String)properties.get(ITerminalsConnectorConstants.PROP_SSH_USER)); + memento.putString(ITerminalsConnectorConstants.PROP_ENCODING, (String)properties.get(ITerminalsConnectorConstants.PROP_ENCODING)); + + // The password is stored within the Eclipse secure preferences -> no need to store it to the memento + // + // If ever needed, this is an example on how to encrypt the password using 3DES. Do not remove! + + /* + String password = properties.getStringProperty(ITerminalsConnectorConstants.PROP_SSH_PASSWORD); + if (password != null) { + try { + // Generate a temporary key. In practice, you would save this key. + // See also Encrypting with DES Using a Pass Phrase. + // SecretKey key = KeyGenerator.getInstance("DESede").generateKey(); + + SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); //$NON-NLS-1$ + SecretKey key = factory.generateSecret(new DESKeySpec((ITerminalsConnectorConstants.PROP_SSH_PASSWORD + ".SshMementoHandler").getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ + + Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); //$NON-NLS-1$ + cipher.init(Cipher.ENCRYPT_MODE, key); + + String encrypedPwd = new String(Base64.encode(cipher.doFinal(password.getBytes("UTF-8")))); //$NON-NLS-1$ + memento.putString(ITerminalsConnectorConstants.PROP_SSH_PASSWORD, encrypedPwd); + } + catch (Exception e) { + if (Platform.inDebugMode()) e.printStackTrace(); + } + } + */ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#restoreState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void restoreState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + + // Restore the terminal properties from the memento + properties.put(ITerminalsConnectorConstants.PROP_IP_HOST, memento.getString(ITerminalsConnectorConstants.PROP_IP_HOST)); + properties.put(ITerminalsConnectorConstants.PROP_IP_PORT, memento.getInteger(ITerminalsConnectorConstants.PROP_IP_PORT)); + properties.put(ITerminalsConnectorConstants.PROP_TIMEOUT, memento.getInteger(ITerminalsConnectorConstants.PROP_TIMEOUT)); + properties.put(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE, memento.getInteger(ITerminalsConnectorConstants.PROP_SSH_KEEP_ALIVE)); + properties.put(ITerminalsConnectorConstants.PROP_SSH_USER, memento.getString(ITerminalsConnectorConstants.PROP_SSH_USER)); + properties.put(ITerminalsConnectorConstants.PROP_ENCODING, memento.getString(ITerminalsConnectorConstants.PROP_ENCODING)); + + // The password is stored within the Eclipse secure preferences -> restore it from there + // To access the secure storage, we need the preference instance + String password = null; + ISecurePreferences preferences = SecurePreferencesFactory.getDefault(); + if (preferences != null && (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST) != null) { + // Construct the secure preferences node key + String nodeKey = "/Target Explorer SSH Password/" + (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST); //$NON-NLS-1$ + ISecurePreferences node = preferences.node(nodeKey); + if (node != null) { + try { + password = node.get("password", null); //$NON-NLS-1$ + } + catch (StorageException ex) { /* ignored on purpose */ } + } + } + + // Example of restoring the password from an 3DES encrypted string. Do not remove! + /* + String encrypedPwd = memento.getString(ITerminalsConnectorConstants.PROP_SSH_PASSWORD); + if (encrypedPwd != null) { + try { + SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); //$NON-NLS-1$ + SecretKey key = factory.generateSecret(new DESKeySpec((ITerminalsConnectorConstants.PROP_SSH_PASSWORD + ".SshMementoHandler").getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ + + Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); //$NON-NLS-1$ + cipher.init(Cipher.DECRYPT_MODE, key); + + byte[] encBytes = Base64.decode(encrypedPwd.getBytes("UTF-8")); //$NON-NLS-1$ + byte[] decBytes = cipher.doFinal(encBytes); + + password = new String(decBytes); + } + catch (Exception e) { + if (Platform.inDebugMode()) e.printStackTrace(); + } + } + */ + + properties.put(ITerminalsConnectorConstants.PROP_SSH_PASSWORD, password); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/nls/Messages.java new file mode 100644 index 00000000000..61978ceb6df --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/nls/Messages.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361352] [TERMINALS][SSH] Add SSH terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.ssh.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.connector.ssh.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String SshLauncherDelegate_terminalTitle; + public static String SshLauncherDelegate_terminalTitle_port; + public static String SshLauncherDelegate_terminalTitle_default; + public static String SshWizardConfigurationPanel_saveUser; + public static String SshWizardConfigurationPanel_savePassword; +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/nls/Messages.properties new file mode 100644 index 00000000000..5a5b7efec5c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.ssh/src/org/eclipse/tm/terminal/connector/ssh/nls/Messages.properties @@ -0,0 +1,17 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +SshLauncherDelegate_terminalTitle=SSH {0}@{1} ({2}) +SshLauncherDelegate_terminalTitle_port=SSH {0}@{1}:{2} ({3}) +SshLauncherDelegate_terminalTitle_default=SSH Terminal +SshWizardConfigurationPanel_saveUser=Save user +SshWizardConfigurationPanel_savePassword=Save password diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.classpath b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.options b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.options new file mode 100644 index 00000000000..77c6a134ddd --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.options @@ -0,0 +1 @@ +org.eclipse.tm.terminal.connector.telnet/debugmode = 0 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.project b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.project new file mode 100644 index 00000000000..83045227a60 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.project @@ -0,0 +1,45 @@ + + + org.eclipse.tm.terminal.connector.telnet + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + + + 1329502098231 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..4754bba05f6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,362 @@ +#Wed Oct 19 12:10:57 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..9cf0892c24c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/META-INF/MANIFEST.MF @@ -0,0 +1,22 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.connector.telnet;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Activator: org.eclipse.tm.terminal.connector.telnet.activator.UIPlugin +Bundle-Vendor: %providerName +Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.equinox.security;bundle-version="1.1.100", + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.view.ui;bundle-version="4.5.0";resolution:=optional, + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.ui;bundle-version="3.8.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.connector.telnet.activator;x-internal:=true, + org.eclipse.tm.terminal.connector.telnet.connector, + org.eclipse.tm.terminal.connector.telnet.controls, + org.eclipse.tm.terminal.connector.telnet.launcher, + org.eclipse.tm.terminal.connector.telnet.nls;x-internal:=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/about.html b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

May 24, 2012

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/build.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/build.properties new file mode 100644 index 00000000000..1c3465df7d0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/build.properties @@ -0,0 +1,18 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + plugin.xml,\ + about.html diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/plugin.properties new file mode 100644 index 00000000000..8e74cc83e2f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/plugin.properties @@ -0,0 +1,22 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal Telnet Connector +providerName = Eclipse.org - Target Management + +# ----- Terminal Connector ----- + +TelnetConnector.label=Telnet + +# ----- Terminal Launcher Delegates ----- + +TelnetLauncherDelegate.label=Telnet Terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/plugin.xml new file mode 100644 index 00000000000..dc9d728cb06 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/plugin.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/pom.xml new file mode 100644 index 00000000000..a6f4f6cdc21 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.connector.telnet + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/activator/UIPlugin.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/activator/UIPlugin.java new file mode 100644 index 00000000000..0f7a167df9c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/activator/UIPlugin.java @@ -0,0 +1,114 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [366374] [TERMINALS][TELNET] Add Telnet terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.activator; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.graphics.Image; +import org.eclipse.tm.terminal.view.core.tracing.TraceHandler; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class UIPlugin extends AbstractUIPlugin { + // The shared instance + private static UIPlugin plugin; + // The trace handler instance + private static volatile TraceHandler traceHandler; + + /** + * The constructor + */ + public UIPlugin() { + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static UIPlugin getDefault() { + return plugin; + } + + /** + * Convenience method which returns the unique identifier of this plugin. + */ + public static String getUniqueIdentifier() { + if (getDefault() != null && getDefault().getBundle() != null) { + return getDefault().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.connector.telnet"; //$NON-NLS-1$ + } + + /** + * Returns the bundles trace handler. + * + * @return The bundles trace handler. + */ + public static TraceHandler getTraceHandler() { + if (traceHandler == null) { + traceHandler = new TraceHandler(getUniqueIdentifier()); + } + return traceHandler; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry) + */ + @Override + protected void initializeImageRegistry(ImageRegistry registry) { + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the Image object instance. + * + * @param key The key the image is registered with. + * @return The Image object instance or null. + */ + public static Image getImage(String key) { + return getDefault().getImageRegistry().get(key); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the ImageDescriptor object instance. + * + * @param key The key the image is registered with. + * @return The ImageDescriptor object instance or null. + */ + public static ImageDescriptor getImageDescriptor(String key) { + return getDefault().getImageRegistry().getDescriptor(key); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/ITelnetSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/ITelnetSettings.java new file mode 100644 index 00000000000..901f06ac34b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/ITelnetSettings.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +/** + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ITelnetSettings { + /** + * @since 4.2 + */ + static final String EOL_CRNUL = "CR+NUL"; //$NON-NLS-1$ + /** + * @since 4.2 + */ + static final String EOL_CRLF = "CR+LF"; //$NON-NLS-1$ + + String getHost(); + int getNetworkPort(); + int getTimeout(); + /** + * @since 4.2 + */ + String getEndOfLine(); + String getSummary(); + void load(ISettingsStore store); + void save(ISettingsStore store); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/NetworkPortMap.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/NetworkPortMap.java new file mode 100644 index 00000000000..87687c231de --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/NetworkPortMap.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalNetworkPortMap + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import java.util.ArrayList; +import java.util.List; + +public class NetworkPortMap { + public static final String PROP_NAMETGTCONS = "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_VALUETGTCONS = "1232"; //$NON-NLS-1$ + public static final String PROP_VALUETELNET = "23"; //$NON-NLS-1$ + + String[][] fPortMap=new String[][] { + // portName, port + {PROP_NAMETGTCONS, PROP_VALUETGTCONS}, + {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/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetCodes.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetCodes.java new file mode 100644 index 00000000000..1d60c75a080 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetCodes.java @@ -0,0 +1,96 @@ +/******************************************************************************* + * Copyright (c) 2005, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Fran Litterio (Wind River) - initial API and implementation + * Helmut Haigermoser (Wind River) - repackaged + * Ted Williams (Wind River) - repackaged into org.eclipse namespace + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +/** + * This interface defines symbolic constants for numeric TELNET protocol command and + * option codes. Any class that needs to use these constants must implement this + * interface. The meanings of these constants are defined in the various TELNET RFCs + * (RFC 854 to RFC 861, and others). + */ +interface TelnetCodes +{ + /** Command code: Subnegotiation End. */ + static final byte TELNET_SE = (byte)240; + + /** Command code: No-op. */ + static final byte TELNET_NOP = (byte)241; + + /** Command code: Data Mark. */ + static final byte TELNET_DM = (byte)242; + + /** Command code: Break. */ + static final byte TELNET_BREAK = (byte)243; + + /** Command code: Interrupt Process. */ + static final byte TELNET_IP = (byte)244; + + /** Command code: Abort Output. */ + static final byte TELNET_AO = (byte)245; + + /** Command code: Are You There. */ + static final byte TELNET_AYT = (byte)246; + + /** Command code: Erase Character. */ + static final byte TELNET_EC = (byte)247; + + /** Command code: Erase Line. */ + static final byte TELNET_EL = (byte)248; + + /** Command code: Go Ahead. */ + static final byte TELNET_GA = (byte)249; + + /** Command code: Subnegotiation Begin. */ + static final byte TELNET_SB = (byte)250; + + /** Command code: Will. */ + static final byte TELNET_WILL = (byte)251; + + /** Command code: Won't. */ + static final byte TELNET_WONT = (byte)252; + + /** Command code: Do. */ + static final byte TELNET_DO = (byte)253; + + /** Command code: Don't. */ + static final byte TELNET_DONT = (byte)254; + + /** Command code: Interpret As Command. */ + static final byte TELNET_IAC = (byte)255; + + /** Command code: IS. */ + static final byte TELNET_IS = 0; + + /** Command code: SEND. */ + static final byte TELNET_SEND = 1; + + + /** Option code: Transmit Binary option. */ + static final byte TELNET_OPTION_TRANSMIT_BINARY = 0; + + /** Option code: Echo option. */ + static final byte TELNET_OPTION_ECHO = 1; + + /** Option code: Suppress Go Ahead option. */ + static final byte TELNET_OPTION_SUPPRESS_GA = 3; + + /** Option code: Terminal Type */ + static final byte TELNET_OPTION_TERMINAL_TYPE = 24; + + /** Option code: Negotitate About Window Size (NAWS) */ + static final byte TELNET_OPTION_NAWS = 31; +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnectWorker.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnectWorker.java new file mode 100644 index 00000000000..330e31c1de1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnectWorker.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalControl + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Uwe Stieber (Wind River) - [287158][terminal][telnet] Connect worker is giving up to early + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketTimeoutException; +import java.net.UnknownHostException; + +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +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); + } + @Override + public void run() { + // Retry the connect with after a little pause in case the + // remote telnet server isn't ready. ConnectExceptions might + // happen if the telnet server process did not initialized itself. + // This is seen especially if the telnet server is a process + // providing it's input and output via a built in telnet server. + int remaining = 10; + + while (remaining >= 0) { + // Pause before we re-try if the remaining tries are less than the initial value + if (remaining < 10) try { Thread.sleep(500); } catch (InterruptedException e) { /* ignored on purpose */ } + + 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); + + // If we get to this point, the connect succeeded and we will + // force the remaining counter to be 0. + remaining = 0; + + // 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) { + // No re-try in case of UnknownHostException, there is no indication that + // the DNS will fix itself + remaining = 0; + //Construct error message and signal failed + 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) { + // Time out occurred. No re-try in this case either. Time out can + // be increased by the user. Multiplying the timeout with the remaining + // counter is not desired. + remaining = 0; + // Construct error message and signal failed + connectFailed(socketTimeoutException.getMessage(), "Connection Error!\n" + socketTimeoutException.getMessage()); //$NON-NLS-1$ + } catch (ConnectException connectException) { + // In case of a ConnectException, do a re-try. The server could have been + // simply not ready yet and the worker would give up to early. If the terminal + // control is already closed (disconnected), don't print "Connection refused" errors + if (remaining == 0 && TerminalState.CLOSED != fControl.getState()) { + connectFailed(connectException.getMessage(),"Connection refused!"); //$NON-NLS-1$ + } + } catch (Exception exception) { + // Any other exception on connect. No re-try in this case either + remaining = 0; + // Log the exception + Logger.logException(exception); + // And signal failed + connectFailed(exception.getMessage(),""); //$NON-NLS-1$ + } finally { + remaining--; + } + } + } + + private void connectFailed(String terminalText, String msg) { + Logger.log(terminalText); + fControl.displayTextInTerminal(terminalText); + fConn.cleanSocket(); + fControl.setState(TerminalState.CLOSED); + fControl.setMsg(msg); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnection.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnection.java new file mode 100644 index 00000000000..67c1e1a2b2c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnection.java @@ -0,0 +1,697 @@ +/******************************************************************************* + * Copyright (c) 2005, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Fran Litterio (Wind River) - initial API and implementation + * Helmut Haigermoser (Wind River) - repackaged + * Ted Williams (Wind River) - repackaged into org.eclipse namespace + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Michael Scharf (Wind River) - [209665] Add ability to log byte streams from terminal + * Alex Panchenko (Xored) - [277061] TelnetConnection.isConnected() should check if socket was not closed + * Uwe Stieber (Wind River) - [281329] Telnet connection not handling "SocketException: Connection reset" correct + * Nils Hagge (Siemens AG) - [276023] close socket streams after connection is disconnected + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; +import java.net.SocketException; + +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +/** + * 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() && !socket.isClosed(); + } + + /** + * 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 = { Integer.valueOf(width), Integer.valueOf(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 displayTextInTerminal(String string) { + terminalControl.displayTextInTerminal(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. + */ + @Override + 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. + + displayTextInTerminal(TelnetMessages.CONNECTION_CLOSED_BY_FOREIGN_HOST); + + // Tell the ITerminalControl object that the connection is + // closed. + terminalControl.setState(TerminalState.CLOSED); + break; + } + + // 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) { + terminalControl.getRemoteToTerminalOutputStream().write(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.equalsIgnoreCase("Socket closed") && !message.equalsIgnoreCase("Connection reset")) //$NON-NLS-1$ //$NON-NLS-2$ + { + Logger.logException(ex); + } + + } catch (Exception ex) { + Logger.logException(ex); + } finally { + // Tell the ITerminalControl object that the connection is closed. + terminalControl.setState(TerminalState.CLOSED); + try { inputStream.close(); } catch(IOException ioe) { /*ignore*/ } + try { outputStream.close(); } catch(IOException ioe) { /*ignore*/ } + } + } + + /** + * 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 sub-negotiation is delegated to instances of TelnetOption. + * + * @return The number of bytes remaining in the buffer after removing all + * TELNET protocol bytes. + */ + //TELNET option state is stored in instances of TelnetOption. + 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]; + int ubyte = inputByte & 0xFF; + + 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++] = inputByte; + } + 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$ + ubyte); + 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[ubyte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + remoteOptions[ubyte].handleWill(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_WONT_RECEIVED: + Logger.log("Received WONT " + localOptions[ubyte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + remoteOptions[ubyte].handleWont(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_DO_RECEIVED: + Logger.log("Received DO " + localOptions[ubyte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + localOptions[ubyte].handleDo(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_DONT_RECEIVED: + Logger.log("Received DONT " + localOptions[ubyte].optionName() + "."); //$NON-NLS-1$ //$NON-NLS-2$ + localOptions[ubyte].handleDont(); + telnetState = STATE_INITIAL; + telnetServerDetected(); + break; + + case STATE_SUBNEGOTIATION_STARTED: + Logger.log("Starting subnegotiation for option " + //$NON-NLS-1$ + localOptions[ubyte].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] & 0xFF; + + 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 " + ubyte); //$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/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnector.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnector.java new file mode 100644 index 00000000000..5ac0865364b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetConnector.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2005, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalControl + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + * Sean Adams (Cisco) - [231959][terminal][telnet] NPE in TelnetConnector.java + * David Sciamma (Anyware-Tech) - [288254][telnet] local echo is always disabled + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.Socket; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +public class TelnetConnector extends TerminalConnectorImpl { + + static final class TelnetOutputStream extends FilterOutputStream { + final static byte CR = 13; + final static byte LF = 10; + final static byte NUL = 0; + final static byte[] CRNUL = { CR, NUL }; + final static byte[] CRLF = { CR, LF }; + final byte[] EOL; + + public TelnetOutputStream(OutputStream outputStream, String endOfLine) { + super(outputStream); + if (ITelnetSettings.EOL_CRLF.equals(endOfLine)) + EOL = CRLF; + else + EOL = CRNUL; + } + + @Override + public void write(int b) throws IOException { + if (b == CR) + out.write(EOL); + else + out.write(b); + } + } + + private OutputStream fOutputStream; + private InputStream fInputStream; + private Socket fSocket; + private TelnetConnection fTelnetConnection; + private final TelnetSettings fSettings; + private int fWidth = -1; + private int fHeight = -1; + + public TelnetConnector() { + this(new TelnetSettings()); + } + public TelnetConnector(TelnetSettings settings) { + fSettings=settings; + } + @Override + public void connect(ITerminalControl control) { + super.connect(control); + fWidth=-1; + fHeight=-1; + // TERM=xterm implies VT100 line wrapping mode + control.setVT100LineWrapping(true); + TelnetConnectWorker worker = new TelnetConnectWorker(this,control); + worker.start(); + } + @Override + public void doDisconnect() { + 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 (getTerminalToRemoteStream() != null) { + try { + getTerminalToRemoteStream().close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + cleanSocket(); + } + @Override + public boolean isLocalEcho() { + if(fTelnetConnection==null) + return false; + return fTelnetConnection.localEcho(); + } + @Override + public void setTerminalSize(int newWidth, int newHeight) { + if(fTelnetConnection!=null && (newWidth!=fWidth || newHeight!=fHeight)) { + //avoid excessive communications due to change size requests by caching previous size + fTelnetConnection.setTerminalSize(newWidth, newHeight); + fWidth=newWidth; + fHeight=newHeight; + } + } + public InputStream getInputStream() { + return fInputStream; + } + @Override + public OutputStream getTerminalToRemoteStream() { + return fOutputStream; + } + private void setInputStream(InputStream inputStream) { + fInputStream = inputStream; + } + private void setOutputStream(OutputStream outputStream) { + if (outputStream == null) { + fOutputStream = null; + return; + } + // translate CR to telnet end-of-line sequence - RFC 854 + fOutputStream = new TelnetOutputStream(outputStream, fSettings.getEndOfLine()); + } + 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 displayTextInTerminal(String text) { + fControl.displayTextInTerminal(text); + } + public OutputStream getRemoteToTerminalOutputStream () { + return fControl.getRemoteToTerminalOutputStream(); + } + public void setState(TerminalState state) { + fControl.setState(state); + } + public ITelnetSettings getTelnetSettings() { + return fSettings; + } + @Override + public void setDefaultSettings() { + fSettings.load(new NullSettingsStore()); + } + @Override + public String getSettingsSummary() { + return fSettings.getSummary(); + } + @Override + public void load(ISettingsStore store) { + fSettings.load(store); + } + @Override + public void save(ISettingsStore store) { + fSettings.save(store); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetMessages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetMessages.java new file mode 100644 index 00000000000..ed3ed05dfa4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetMessages.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import org.eclipse.osgi.util.NLS; + +public class TelnetMessages extends NLS { + static { + NLS.initializeMessages(TelnetMessages.class.getName(), TelnetMessages.class); + } + public static String PORT; + public static String HOST; + public static String CONNECTION_CLOSED_BY_FOREIGN_HOST; + public static String TIMEOUT; + /** + * @since 4.2 + */ + public static String END_OF_LINE; + + } diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetMessages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetMessages.properties new file mode 100644 index 00000000000..77acc43ec40 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetMessages.properties @@ -0,0 +1,23 @@ +############################################################################### +# Copyright (c) 2005, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Initial Contributors: +# The following Wind River employees contributed to the Terminal component +# that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, +# Helmut Haigermoser and Ted Williams. +# +# Contributors: +# Michael Scharf (Wind River) - split into core, view and connector plugins +# Martin Oberhuber (Wind River) - fixed copyright headers and beautified +############################################################################### +PORT = Port +HOST = Host +CONNECTION_CLOSED_BY_FOREIGN_HOST= Connection closed by foreign host. +TIMEOUT = Timeout (sec) +END_OF_LINE = End of Line \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetOption.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetOption.java new file mode 100644 index 00000000000..e97c9a1baa6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetOption.java @@ -0,0 +1,701 @@ +/******************************************************************************* + * Copyright (c) 2005, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [267181] Fix telnet option negotiation loop + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.Date; + +import org.eclipse.tm.internal.terminal.provisional.api.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 labeled 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 negotiation + * 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 & 0xFF]; + } + + /** + * 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 "xterm"). + * + * @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 "xterm" using this sequence + // of TELNET protocol bytes: + // + // IAC SB TERMINAL-TYPE IS x t e r m IAC SE + + byte[] terminalTypeData = { TELNET_IAC, TELNET_SB, + TELNET_OPTION_TERMINAL_TYPE, TELNET_IS, (byte) 'x', + (byte) 't', (byte) 'e', (byte) 'r', (byte) 'm', 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 + + final 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$ + + // 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). + + Thread t=new Thread() { + @Override + public void run() { + try { + outputStream.write(NAWSData); + } catch (IOException ex) { + Logger.log("IOException sending NAWS subnegotiation!"); //$NON-NLS-1$ + Logger.logException(ex); + } + } + }; + t.setDaemon(true); + t.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/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetProperties.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetProperties.java new file mode 100644 index 00000000000..0af9feaa8f6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetProperties.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalProperties + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +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/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetSettings.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetSettings.java new file mode 100644 index 00000000000..40d8ca5f492 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetSettings.java @@ -0,0 +1,106 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalSettings + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +/** + * @noreference This class is not intended to be referenced by clients. + */ +public class TelnetSettings implements ITelnetSettings { + protected String fHost; + protected String fNetworkPort; + protected String fTimeout; + protected String fEndOfLine = EOL_CRNUL; + private final TelnetProperties fProperties=new TelnetProperties(); + @Override + public String getHost() { + return fHost; + } + + public void setHost(String strHost) { + fHost = strHost; + } + + public String getNetworkPortString() { + return fNetworkPort; + } + + @Override + public int getNetworkPort() { + try { + return Integer.parseInt(fNetworkPort); + } catch (NumberFormatException numberFormatException) { + return 1313; + } + } + + public void setNetworkPort(String strNetworkPort) { + fNetworkPort = strNetworkPort; + } + + @Override + public String getSummary() { + return getHost() + ":" + getNetworkPortString(); //$NON-NLS-1$ + } + + @Override + public void load(ISettingsStore store) { + fHost = store.get("Host", fProperties.getDefaultHost());//$NON-NLS-1$ + fNetworkPort = store.get("NetworkPort", fProperties.getDefaultNetworkPort());//$NON-NLS-1$ + fTimeout = store.get("Timeout","10");//$NON-NLS-1$ //$NON-NLS-2$ + fEndOfLine = store.get("EndOfLine", EOL_CRNUL);//$NON-NLS-1$ + } + + @Override + public void save(ISettingsStore store) { + store.put("Host", fHost);//$NON-NLS-1$ + store.put("NetworkPort", fNetworkPort);//$NON-NLS-1$ + store.put("Timeout", fTimeout);//$NON-NLS-1$ + store.put("EndOfLine", fEndOfLine);//$NON-NLS-1$ + } + + public TelnetProperties getProperties() { + return fProperties; + } + @Override + 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; + } + + public void setEndOfLine(String eol) { + fEndOfLine = EOL_CRLF.equals(eol) ? EOL_CRLF : EOL_CRNUL; + } + + @Override + public String getEndOfLine() { + return fEndOfLine; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetSettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetSettingsPage.java new file mode 100644 index 00000000000..f40cfb76e9f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/connector/TelnetSettingsPage.java @@ -0,0 +1,246 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalSettingsDlg + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [206917] Add validation for Terminal Settings + * Martin Oberhuber (Wind River) - [401476] Strip whitespace around Telnet Port + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.connector; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +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.Label; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; + +public class TelnetSettingsPage extends AbstractSettingsPage { + /* default */ Text fHostText; + /* default */ Combo fNetworkPortCombo; + /* default */ Text fTimeout; + /* default */ Combo fEndOfLineCombo; + private final TelnetSettings fTerminalSettings; + + public TelnetSettingsPage(TelnetSettings settings) { + fTerminalSettings=settings; + } + @Override + public void saveSettings() { + fTerminalSettings.setHost(fHostText.getText()); + fTerminalSettings.setTimeout(fTimeout.getText()); + fTerminalSettings.setNetworkPort(getNetworkPort()); + fTerminalSettings.setEndOfLine(getEndOfLine()); + } + + @Override + public void loadSettings() { + if(fTerminalSettings!=null) { + setHost(fTerminalSettings.getHost()); + setTimeout(fTerminalSettings.getTimeoutString()); + setNetworkPort(fTerminalSettings.getNetworkPortString()); + setEndOfLine(fTerminalSettings.getEndOfLine()); + } + } + 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) { + if (strNetworkPort!=null) { + String strPortName = getNetworkPortMap().findPortName(strNetworkPort); + if(strPortName==null) { + strPortName=strNetworkPort; //fallback to verbatim port if not found + } + int nIndex = fNetworkPortCombo.indexOf(strPortName); + + if (nIndex == -1) { + fNetworkPortCombo.setText(strNetworkPort); + } else { + fNetworkPortCombo.select(nIndex); + } + } + } + private String getNetworkPort() { + String portText = fNetworkPortCombo.getText().trim(); + String mappedPort = getNetworkPortMap().findPort(portText); + return mappedPort!=null ? mappedPort : portText; + } + private NetworkPortMap getNetworkPortMap() { + return fTerminalSettings.getProperties().getNetworkPortMap(); + } + private void setEndOfLine(String eol) { + int idx = fEndOfLineCombo.indexOf(eol); + fEndOfLineCombo.select(idx >= 0 ? idx : 0); + } + private String getEndOfLine() { + return fEndOfLineCombo.getText(); + } + @Override + public boolean validateSettings() { + String message = null; + int messageType = IMessageProvider.NONE; + boolean valid = true; + + if (fHostText.getText().trim().length() == 0) { + String m = "Please enter a host IP or name."; //$NON-NLS-1$ + int mt = IMessageProvider.INFORMATION; + updateControlDecoration(fHostText, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fHostText, null, IMessageProvider.NONE); + } + + try { + int p = Integer.parseInt(getNetworkPort()); + if (p <= 0 || p > 65535) { + String m = "Invalid network port. Must be between 0 and 65535."; //$NON-NLS-1$ + int mt = IMessageProvider.ERROR; + updateControlDecoration(fNetworkPortCombo, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fNetworkPortCombo, null, IMessageProvider.NONE); + } + + p = Integer.parseInt(fTimeout.getText().trim()); + if (p < 0) { + String m = "Invalid timeout. Must be greater than 0."; //$NON-NLS-1$ + int mt = IMessageProvider.ERROR; + updateControlDecoration(fTimeout, m, mt); + if (mt > messageType) { message = m; messageType = mt; } + + valid = false; + } else { + updateControlDecoration(fTimeout, null, IMessageProvider.NONE); + } + + } catch (Exception e) { + valid = false; + } + + setMessage(message, messageType); + return valid; + } + + @Override + 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); + gridData.horizontalIndent = FieldDecorationRegistry.getDefault().getMaximumDecorationWidth(); + + 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); + fHostText.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + fireListeners(fHostText); + } + }); + createControlDecoration(fHostText); + + // 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); + fNetworkPortCombo.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + fireListeners(fNetworkPortCombo); + } + }); + fNetworkPortCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + fireListeners(fNetworkPortCombo); + } + }); + createControlDecoration(fNetworkPortCombo); + + 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)); + fTimeout.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + fireListeners(fTimeout); + } + }); + createControlDecoration(fTimeout); + + new Label(composite, SWT.RIGHT).setText(TelnetMessages.END_OF_LINE + ":"); //$NON-NLS-1$ + gridData = new GridData(GridData.FILL_HORIZONTAL); + fEndOfLineCombo = new Combo(composite, SWT.DROP_DOWN | SWT.READ_ONLY); + fEndOfLineCombo.setLayoutData(gridData); + fEndOfLineCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + fireListeners(fEndOfLineCombo); + } + }); + loadCombo(fEndOfLineCombo, Arrays.asList(ITelnetSettings.EOL_CRNUL, ITelnetSettings.EOL_CRLF)); + + loadSettings(); + } + private void loadCombo(Combo ctlCombo, List table) { + for (Iterator iter = table.iterator(); iter.hasNext();) { + String label = iter.next(); + ctlCombo.add(label); + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/controls/TelnetWizardConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/controls/TelnetWizardConfigurationPanel.java new file mode 100644 index 00000000000..05ca464dbc6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/controls/TelnetWizardConfigurationPanel.java @@ -0,0 +1,219 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [366374] [TERMINALS][TELNET] Add Telnet terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.controls; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tm.internal.terminal.provisional.api.AbstractSettingsPage; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage; +import org.eclipse.tm.terminal.connector.telnet.connector.NetworkPortMap; +import org.eclipse.tm.terminal.connector.telnet.connector.TelnetConnector; +import org.eclipse.tm.terminal.connector.telnet.connector.TelnetSettings; +import org.eclipse.tm.terminal.connector.telnet.connector.TelnetSettingsPage; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; + +/** + * telnet wizard configuration panel implementation. + */ +public class TelnetWizardConfigurationPanel extends AbstractExtendedConfigurationPanel { + + public TelnetSettings telnetSettings; + private ISettingsPage telnetSettingsPage; + + /** + * Constructor. + * + * @param container The configuration panel container or null. + */ + public TelnetWizardConfigurationPanel(IConfigurationPanelContainer container) { + super(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupPanel(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + panel.setLayoutData(data); + + // Create the host selection combo + if (isWithoutSelection()) createHostsUI(panel, true); + + TelnetConnector conn = new TelnetConnector(); + telnetSettings = (TelnetSettings) conn.getTelnetSettings(); + telnetSettings.setHost(getSelectionHost()); + // MWE otherwise we don't get a valid default selection of the combo + telnetSettings.setNetworkPort(NetworkPortMap.PROP_VALUETELNET); + + telnetSettingsPage = new TelnetSettingsPage(telnetSettings); + if (telnetSettingsPage instanceof AbstractSettingsPage) { + ((AbstractSettingsPage)telnetSettingsPage).setHasControlDecoration(true); + } + telnetSettingsPage.createControl(panel); + + // Add the listener to the settings page + telnetSettingsPage.addListener(new ISettingsPage.Listener() { + + @Override + public void onSettingsPageChanged(Control control) { + if (getContainer() != null) getContainer().validate(); + } + }); + + // Create the encoding selection combo + createEncodingUI(panel, true); + + setControl(panel); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#setupData(java.util.Map) + */ + @Override + public void setupData(Map data) { + if (data == null || telnetSettings == null || telnetSettingsPage == null) return; + + String value = (String)data.get(ITerminalsConnectorConstants.PROP_IP_HOST); + if (value != null) telnetSettings.setHost(value); + + Object v = data.get(ITerminalsConnectorConstants.PROP_IP_PORT); + value = v != null ? v.toString() : null; + if (value != null) telnetSettings.setNetworkPort(value); + + v = data.get(ITerminalsConnectorConstants.PROP_TIMEOUT); + value = v != null ? v.toString() : null; + if (value != null) telnetSettings.setTimeout(value); + + v = data.get(ITerminalsConnectorConstants.PROP_TELNET_EOL); + value = v != null ? v.toString() : null; + if (value != null) telnetSettings.setEndOfLine(value); + + value = (String)data.get(ITerminalsConnectorConstants.PROP_ENCODING); + if (value != null) setEncoding(value); + + telnetSettingsPage.loadSettings(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#extractData(java.util.Map) + */ + @Override + public void extractData(Map data) { + if (data == null) return; + + // set the terminal connector id for ssh + data.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, "org.eclipse.tm.terminal.connector.telnet.TelnetConnector"); //$NON-NLS-1$ + + telnetSettingsPage.saveSettings(); + data.put(ITerminalsConnectorConstants.PROP_IP_HOST,telnetSettings.getHost()); + data.put(ITerminalsConnectorConstants.PROP_IP_PORT, Integer.valueOf(telnetSettings.getNetworkPort())); + data.put(ITerminalsConnectorConstants.PROP_TIMEOUT, Integer.valueOf(telnetSettings.getTimeout())); + data.put(ITerminalsConnectorConstants.PROP_TELNET_EOL, telnetSettings.getEndOfLine()); + data.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#fillSettingsForHost(java.lang.String) + */ + @Override + protected void fillSettingsForHost(String host){ + if (host != null && host.length() != 0){ + if (hostSettingsMap.containsKey(host)){ + Map hostSettings = hostSettingsMap.get(host); + if (hostSettings.get(ITerminalsConnectorConstants.PROP_IP_HOST) != null) { + telnetSettings.setHost(hostSettings.get(ITerminalsConnectorConstants.PROP_IP_HOST)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_IP_PORT) != null) { + telnetSettings.setNetworkPort(hostSettings.get(ITerminalsConnectorConstants.PROP_IP_PORT)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_TIMEOUT) != null) { + telnetSettings.setTimeout(hostSettings.get(ITerminalsConnectorConstants.PROP_TIMEOUT)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_TELNET_EOL) != null) { + telnetSettings.setEndOfLine(hostSettings.get(ITerminalsConnectorConstants.PROP_TELNET_EOL)); + } + if (hostSettings.get(ITerminalsConnectorConstants.PROP_ENCODING) != null) { + setEncoding(hostSettings.get(ITerminalsConnectorConstants.PROP_ENCODING)); + } + } else { + telnetSettings.setHost(getSelectionHost()); + // MWE otherwise we don't get a valid default selection of the combo + telnetSettings.setNetworkPort(NetworkPortMap.PROP_VALUETELNET); + } + // set settings in page + telnetSettingsPage.loadSettings(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#saveSettingsForHost(boolean) + */ + @Override + protected void saveSettingsForHost(boolean add){ + String host = getHostFromSettings(); + if(host != null && host.length() != 0) { + Map hostSettings = hostSettingsMap.get(host); + if (hostSettings == null && !add) { + hostSettings=new HashMap(); + hostSettingsMap.put(host, hostSettings); + } + if (hostSettings != null) { + hostSettings.put(ITerminalsConnectorConstants.PROP_IP_HOST, telnetSettings.getHost()); + hostSettings.put(ITerminalsConnectorConstants.PROP_IP_PORT, Integer.toString(telnetSettings.getNetworkPort())); + hostSettings.put(ITerminalsConnectorConstants.PROP_TIMEOUT, Integer.toString(telnetSettings.getTimeout())); + hostSettings.put(ITerminalsConnectorConstants.PROP_TELNET_EOL, telnetSettings.getEndOfLine()); + if (getEncoding() != null) { + hostSettings.put(ITerminalsConnectorConstants.PROP_ENCODING, getEncoding()); + } + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#isValid() + */ + @Override + public boolean isValid(){ + return isEncodingValid() && telnetSettingsPage.validateSettings(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#doSaveWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + saveSettingsForHost(true); + super.doSaveWidgetValues(settings, idPrefix); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#getHostFromSettings() + */ + @Override + protected String getHostFromSettings() { + telnetSettingsPage.saveSettings(); + return telnetSettings.getHost(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/launcher/TelnetLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/launcher/TelnetLauncherDelegate.java new file mode 100644 index 00000000000..98221f60b71 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/launcher/TelnetLauncherDelegate.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [366374] [TERMINALS][TELNET] Add Telnet terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.launcher; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.connector.telnet.connector.TelnetSettings; +import org.eclipse.tm.terminal.connector.telnet.controls.TelnetWizardConfigurationPanel; +import org.eclipse.tm.terminal.connector.telnet.nls.Messages; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +/** + * Telnet launcher delegate implementation. + */ +@SuppressWarnings("restriction") +public class TelnetLauncherDelegate extends AbstractLauncherDelegate { + // The Telnet terminal connection memento handler + private final IMementoHandler mementoHandler = new TelnetMementoHandler(); + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#needsUserConfiguration() + */ + @Override + public boolean needsUserConfiguration() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getPanel(org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer) + */ + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return new TelnetWizardConfigurationPanel(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#execute(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void execute(Map properties, ITerminalService.Done done) { + Assert.isNotNull(properties); + + // Set the terminal tab title + String terminalTitle = getTerminalTitle(properties); + if (terminalTitle != null) { + properties.put(ITerminalsConnectorConstants.PROP_TITLE, terminalTitle); + } + + // For Telnet terminals, force a new terminal tab each time it is launched, + // if not set otherwise from outside + if (!properties.containsKey(ITerminalsConnectorConstants.PROP_FORCE_NEW)) { + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, Boolean.TRUE); + } + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + + /** + * Returns the terminal title string. + *

+ * The default implementation constructs a title like "Telnet @ host (Start time) ". + * + * @return The terminal title string or null. + */ + private String getTerminalTitle(Map properties) { + // Try to see if the user set a title explicitly via the properties map. + String title = getDefaultTerminalTitle(properties); + if (title != null) return title; + + //No title,try to calculate the title + String host = (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST); + + if (host != null) { + DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + String date = format.format(new Date(System.currentTimeMillis())); + return NLS.bind(Messages.TelnetLauncherDelegate_terminalTitle, new String[]{host, date}); + } + + return Messages.TelnetLauncherDelegate_terminalTitle_default; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.PlatformObject#getAdapter(java.lang.Class) + */ + @Override + public Object getAdapter(Class adapter) { + if (IMementoHandler.class.equals(adapter)) { + return mementoHandler; + } + return super.getAdapter(adapter); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#createTerminalConnector(java.util.Map) + */ + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String)properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) connectorId = "org.eclipse.tm.terminal.connector.telnet.TelnetConnector"; //$NON-NLS-1$ + + // Extract the telnet properties + String host = (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST); + Object value = properties.get(ITerminalsConnectorConstants.PROP_IP_PORT); + String port = value != null ? value.toString() : null; + value = properties.get(ITerminalsConnectorConstants.PROP_TIMEOUT); + String timeout = value != null ? value.toString() : null; + String endOfLine = (String)properties.get(ITerminalsConnectorConstants.PROP_TELNET_EOL); + + int portOffset = 0; + if (properties.get(ITerminalsConnectorConstants.PROP_IP_PORT_OFFSET) instanceof Integer) { + portOffset = ((Integer)properties.get(ITerminalsConnectorConstants.PROP_IP_PORT_OFFSET)).intValue(); + if (portOffset < 0) portOffset = 0; + } + + // The real port to connect to is port + portOffset + if (port != null) { + port = Integer.toString(Integer.decode(port).intValue() + portOffset); + } + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the telnet settings + TelnetSettings telnetSettings = new TelnetSettings(); + telnetSettings.setHost(host); + telnetSettings.setNetworkPort(port); + if (timeout != null) { + telnetSettings.setTimeout(timeout); + } + telnetSettings.setEndOfLine(endOfLine); + // And save the settings to the store + telnetSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + return connector; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/launcher/TelnetMementoHandler.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/launcher/TelnetMementoHandler.java new file mode 100644 index 00000000000..ea8a4be6b65 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/launcher/TelnetMementoHandler.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.launcher; + +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.ui.IMemento; + +/** + * Telnet terminal connection memento handler implementation. + */ +public class TelnetMementoHandler implements IMementoHandler { + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#saveState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void saveState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + + // Do not write the terminal title to the memento -> needs to + // be recreated at the time of restoration. + memento.putString(ITerminalsConnectorConstants.PROP_IP_HOST, (String)properties.get(ITerminalsConnectorConstants.PROP_IP_HOST)); + Object value = properties.get(ITerminalsConnectorConstants.PROP_IP_PORT); + memento.putInteger(ITerminalsConnectorConstants.PROP_IP_PORT, value instanceof Integer ? ((Integer)value).intValue() : -1); + value = properties.get(ITerminalsConnectorConstants.PROP_TIMEOUT); + memento.putInteger(ITerminalsConnectorConstants.PROP_TIMEOUT, value instanceof Integer ? ((Integer)value).intValue() : -1); + memento.putString(ITerminalsConnectorConstants.PROP_ENCODING, (String)properties.get(ITerminalsConnectorConstants.PROP_ENCODING)); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler#restoreState(org.eclipse.ui.IMemento, java.util.Map) + */ + @Override + public void restoreState(IMemento memento, Map properties) { + Assert.isNotNull(memento); + Assert.isNotNull(properties); + + // Restore the terminal properties from the memento + properties.put(ITerminalsConnectorConstants.PROP_IP_HOST, memento.getString(ITerminalsConnectorConstants.PROP_IP_HOST)); + properties.put(ITerminalsConnectorConstants.PROP_IP_PORT, memento.getInteger(ITerminalsConnectorConstants.PROP_IP_PORT)); + properties.put(ITerminalsConnectorConstants.PROP_TIMEOUT, memento.getInteger(ITerminalsConnectorConstants.PROP_TIMEOUT)); + properties.put(ITerminalsConnectorConstants.PROP_ENCODING, memento.getString(ITerminalsConnectorConstants.PROP_ENCODING)); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/nls/Messages.java new file mode 100644 index 00000000000..d223e942a6c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/nls/Messages.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [366374] [TERMINALS][TELNET] Add Telnet terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.connector.telnet.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.connector.telnet.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String TelnetLauncherDelegate_terminalTitle; + public static String TelnetLauncherDelegate_terminalTitle_default; +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/nls/Messages.properties new file mode 100644 index 00000000000..7ed5b2ef78d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.connector.telnet/src/org/eclipse/tm/terminal/connector/telnet/nls/Messages.properties @@ -0,0 +1,14 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +TelnetLauncherDelegate_terminalTitle=Telnet {0} ({1}) +TelnetLauncherDelegate_terminalTitle_default=Telnet Terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.classpath b/terminal/plugins/org.eclipse.tm.terminal.control/.classpath new file mode 100644 index 00000000000..25d360efcad --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.cvsignore b/terminal/plugins/org.eclipse.tm.terminal.control/.cvsignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.control/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.options b/terminal/plugins/org.eclipse.tm.terminal.control/.options new file mode 100644 index 00000000000..7e591a4d4e7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.options @@ -0,0 +1,3 @@ +org.eclipse.tm.terminal.control/debug/log = false +org.eclipse.tm.terminal.control/debug/log/char = false +org.eclipse.tm.terminal.control/debug/log/VT100Backend = false diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.project b/terminal/plugins/org.eclipse.tm.terminal.control/.project new file mode 100644 index 00000000000..11e18c380e4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.project @@ -0,0 +1,34 @@ + + + org.eclipse.tm.terminal.control + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.settings/org.eclipse.core.resources.prefs b/terminal/plugins/org.eclipse.tm.terminal.control/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 00000000000..775bde20f32 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,2 @@ +eclipse.preferences.version=1 +encoding//src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java=UTF-8 diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.control/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..eb9982c343a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,100 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=disabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore +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.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +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.unusedObjectAllocation=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +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.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/HelpContexts.xml b/terminal/plugins/org.eclipse.tm.terminal.control/HelpContexts.xml new file mode 100644 index 00000000000..2bde74230c5 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/HelpContexts.xml @@ -0,0 +1,18 @@ + + + + + + The Terminal View supports direct connections to remote systems via serial or network connections. + + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..5150cac4ff8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.control; singleton:=true +Bundle-Version: 4.5.102.qualifier +Bundle-Activator: org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Require-Bundle: org.eclipse.core.runtime, + org.eclipse.ui +Bundle-ActivationPolicy: lazy +Eclipse-LazyStart: true +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ClassPath: . +Export-Package: org.eclipse.tm.internal.terminal.connector;x-internal:=true, + org.eclipse.tm.internal.terminal.control, + org.eclipse.tm.internal.terminal.control.actions, + org.eclipse.tm.internal.terminal.control.impl;x-internal:=true, + org.eclipse.tm.internal.terminal.emulator;x-internal:=true, + org.eclipse.tm.internal.terminal.model;x-internal:=true, + org.eclipse.tm.internal.terminal.preferences, + org.eclipse.tm.internal.terminal.provisional.api, + org.eclipse.tm.internal.terminal.provisional.api.provider, + org.eclipse.tm.internal.terminal.textcanvas;x-internal:=true, + org.eclipse.tm.terminal.model diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/README.txt b/terminal/plugins/org.eclipse.tm.terminal.control/README.txt new file mode 100644 index 00000000000..c88bc696e29 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/README.txt @@ -0,0 +1,18 @@ +Terminal README +=============== + +The Terminal is a UI-less model of a grid of characters, +plus an SWT widget that's updated asynchronously for +maximum performance. The widget can be hooked up to various +ITerminalConnectors providing an InputStream, OutputStream, +and a method for setting the Terminal Size. + +The widget 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.). + +This is not yet a fully compliant vt100 / vt102 terminal +emulator! + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/about.html b/terminal/plugins/org.eclipse.tm.terminal.control/about.html new file mode 100644 index 00000000000..62cf4ee7eb8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

About This Content

+ +

June 5, 2007

+

License

+ +

The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

+ +

If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

+ + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/about.ini b/terminal/plugins/org.eclipse.tm.terminal.control/about.ini new file mode 100644 index 00000000000..3adc27ab587 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/about.ini @@ -0,0 +1,27 @@ +# about.ini +# contains information about a feature +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# "%key" are externalized strings defined in about.properties +# This file does not need to be translated. + +# Property "aboutText" contains blurb for "About" dialog (translated) +aboutText=%blurb + +# Property "windowImage" contains path to window icon (16x16) +# needed for primary features only + +# Property "featureImage" contains path to feature image (32x32) +featureImage=tm32.png + +# Property "aboutImage" contains path to product image (500x330 or 115x164) +# needed for primary features only + +# Property "appName" contains name of the application (not translated) +# needed for primary features only + +# Property "welcomePage" contains path to welcome page (special XML-based format) +# optional + +# Property "welcomePerspective" contains the id of the perspective in which the +# welcome page is to be opened. +# optional \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/about.properties b/terminal/plugins/org.eclipse.tm.terminal.control/about.properties new file mode 100644 index 00000000000..55d889e964e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/about.properties @@ -0,0 +1,24 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Martin Oberhuber - initial API and implementation +################################################################################ +# about.properties +# contains externalized strings for about.ini +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# fill-ins are supplied by about.mappings +# This file should be translated. +# +# Do not translate any values surrounded by {} + +blurb=Target Management Terminal Widget\n\ +\n\ +Version: {featureVersion}\n\ +\n\ +(c) Copyright Wind River Systems, Inc. and others 2003, 2018. All rights reserved.\n\ +Visit http://www.eclipse.org/tm diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/build.properties b/terminal/plugins/org.eclipse.tm.terminal.control/build.properties new file mode 100644 index 00000000000..ff0b66ba638 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/build.properties @@ -0,0 +1,38 @@ +############################################################################### +# Copyright (c) 2003, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Initial Contributors: +# The following Wind River employees contributed to the Terminal component +# that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, +# Helmut Haigermoser and Ted Williams. +# +# Contributors: +# Michael Scharf (Wind River) - split into core, view and connector plugins +# Martin Oberhuber (Wind River) - fixed copyright headers and beautified +# Anna Dushistova (MontaVista) - added icons +############################################################################### +bin.includes = .,\ + META-INF/,\ + plugin.xml,\ + plugin.properties,\ + .options,\ + README.txt,\ + about.html,\ + about.ini,\ + about.properties,\ + tm32.png,\ + icons/,\ + HelpContexts.xml,\ + css/ + +source.. = src/ +output.. = bin/ +src.includes = schema/,\ + about.html + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/css/org.eclipse.tm.terminal.stylesheet.dark.css b/terminal/plugins/org.eclipse.tm.terminal.control/css/org.eclipse.tm.terminal.stylesheet.dark.css new file mode 100644 index 00000000000..6b612015089 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/css/org.eclipse.tm.terminal.stylesheet.dark.css @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2014, 2015 vogella GmbH and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Lars Vogel - initial API and implementation + ******************************************************************************/ + +IEclipsePreferences#org-eclipse-tm-terminal-control { + preferences: + "TerminalPrefInvertColors=true" +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/icons/clcl16/clear_co.gif b/terminal/plugins/org.eclipse.tm.terminal.control/icons/clcl16/clear_co.gif new file mode 100644 index 00000000000..af30a42f83d Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.control/icons/clcl16/clear_co.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/icons/dlcl16/clear_co.gif b/terminal/plugins/org.eclipse.tm.terminal.control/icons/dlcl16/clear_co.gif new file mode 100644 index 00000000000..6775edfabb9 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.control/icons/dlcl16/clear_co.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/icons/elcl16/clear_co.gif b/terminal/plugins/org.eclipse.tm.terminal.control/icons/elcl16/clear_co.gif new file mode 100644 index 00000000000..af30a42f83d Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.control/icons/elcl16/clear_co.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.control/plugin.properties new file mode 100644 index 00000000000..daad8a7fc59 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/plugin.properties @@ -0,0 +1,44 @@ +############################################################################### +# Copyright (c) 2003 - 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Initial Contributors: +# The following Wind River employees contributed to the Terminal component +# that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, +# Helmut Haigermoser and Ted Williams. +# +# Contributors: +# Michael Scharf (Wind River) - split into core, view and connector plugins +# Martin Oberhuber (Wind River) - fixed copyright headers and beautified +# Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget +############################################################################### + +# NLS_MESSAGEFORMAT_NONE + +pluginName = Terminal Control (Embeddable Widget) +providerName = Eclipse.org - Target Management + +terminal.context.name.edit=Terminal Control in Focus +terminal.context.description.edit=Show modified keyboard shortcuts in context menu + +terminal.context.name.terminal=Terminal Typing Connected +terminal.context.description.terminal=Override ALT+x menu access keys while typing into the Terminal + +terminal.insertion.description=Terminal view insertion +terminal.insertion.name=Terminal view insert +terminal.insertion.category.name=Terminal view commands +terminal.view.insertion.description = Terminal view commands + +terminal.command.copy.name=Copy +terminal.command.paste.name=Paste +terminal.command.maximize.name=Maximize Active View or Editor +terminal.command.quickaccess.name=Quick Access + +terminal.preferences.name = Terminal +terminal.font.description = The font for the terminal console. +terminal.font.label = Terminal Console Font diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.control/plugin.xml new file mode 100644 index 00000000000..ed656d41978 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/plugin.xml @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + %terminal.font.description + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.control/pom.xml new file mode 100644 index 00000000000..a0de87da146 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/pom.xml @@ -0,0 +1,27 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + 4.5.102-SNAPSHOT + + org.eclipse.tm.terminal.control + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/schema/connectors.exsd b/terminal/plugins/org.eclipse.tm.terminal.control/schema/connectors.exsd new file mode 100644 index 00000000000..8a0862cf413 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/schema/connectors.exsd @@ -0,0 +1,111 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A class extending TerminalConnectorImpl + + + + + + + + + + Uniquely identify this connector for programmatic access. Clients will use this ID in order to find and instantiate it. + + + + + + + The name of the connection (used in the UI) + + + + + + + + + + When set to "true", the terminal connector will not be visible to the user in connector selections. + + + + + + + + + + + + + + + + Copyright (c) 2006 - 2018 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 2.0 +which accompanies this distribution, and is available at +https://www.eclipse.org/legal/epl-2.0/ + +Contributors: +Michael Scharf (Wind River) - initial API and implementation +Martin Oberhuber (Wind River) - fixed copyright headers and beautified +Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/connector/TerminalConnector.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/connector/TerminalConnector.java new file mode 100644 index 00000000000..dfa2f8faf91 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/connector/TerminalConnector.java @@ -0,0 +1,225 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Michael Scharf (Wind River) - [200541] Extract from TerminalConnectorExtension.TerminalConnectorProxy + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + * Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.connector; + +import java.io.OutputStream; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.Platform; +import org.eclipse.tm.internal.terminal.control.impl.TerminalMessages; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +/** + * An {@link ITerminalConnector} instance, also known as terminal connection + * type, for maintaining a single terminal connection. + * + * It provides all terminal connector functions that can be provided by static + * markup without loading the actual implementation class. The actual + * {@link TerminalConnectorImpl} implementation class is lazily loaded by the + * provided {@link TerminalConnector.Factory} interface when needed. class, and + * delegates to the actual implementation when needed. The following methods can + * be called without initializing the contributed implementation class: + * {@link #getId()}, {@link #getName()}, {@link #getSettingsSummary()},{@link #load(ISettings)}, + * {@link #setTerminalSize(int, int)}, {@link #save(ISettings)}, + * {@link #getAdapter(Class)} + * + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * Clients can get terminal connector instances through the + * {@link TerminalConnectorExtension} class. + * @since org.eclipse.tm.terminal 2.0 + */ +public class TerminalConnector implements ITerminalConnector { + /** + * Creates an instance of TerminalConnectorImpl. This is used to lazily load + * classed defined in extensions. + * + * @since org.eclipse.tm.terminal 2.0 + */ + public interface Factory { + /** + * Factory method to create the actual terminal connector implementation + * when needed. + * + * @return a Connector + * @throws Exception + */ + TerminalConnectorImpl makeConnector() throws Exception; + } + /** + * The factory for creating impl instances. + */ + private final TerminalConnector.Factory fTerminalConnectorFactory; + /** + * The (display) name of the TerminalConnector + */ + private final String fName; + /** + * The unique id the connector + */ + private final String fId; + /** + * Flag to mark the connector as hidden. + */ + private final boolean fHidden; + /** + * The connector + */ + private TerminalConnectorImpl fConnector; + /** + * If the initialization of the class specified in the extension fails, + * this variable contains the error + */ + private Exception fException; + /** + * The store might be set before the real connector is initialized. + * This keeps the value until the connector is created. + */ + private ISettingsStore fStore; + /** + * Constructor for the terminal connector. + * + * @param terminalConnectorFactory Factory for lazily instantiating the + * TerminalConnectorImpl when needed. + * @param id terminal connector ID. The connector is publicly known under + * this ID. + * @param name translatable name to display the connector in the UI. + */ + public TerminalConnector(TerminalConnector.Factory terminalConnectorFactory, String id, String name, boolean hidden) { + fTerminalConnectorFactory = terminalConnectorFactory; + fId = id; + fName = name; + fHidden = hidden; + } + public String getInitializationErrorMessage() { + getConnectorImpl(); + if(fException!=null) + return fException.getLocalizedMessage(); + return null; + } + public String getId() { + return fId; + } + public String getName() { + return fName; + } + public boolean isHidden() { + return fHidden; + } + private TerminalConnectorImpl getConnectorImpl() { + if(!isInitialized()) { + try { + fConnector=fTerminalConnectorFactory.makeConnector(); + fConnector.initialize(); + } catch (Exception e) { + fException=e; + fConnector=new TerminalConnectorImpl(){ + public void connect(ITerminalControl control) { + // super.connect(control); + control.setState(TerminalState.CLOSED); + control.setMsg(getInitializationErrorMessage()); + } + public OutputStream getTerminalToRemoteStream() { + return null; + } + public String getSettingsSummary() { + return null; + }}; + // that's the place where we log the exception + Logger.logException(e); + } + if(fConnector!=null && fStore!=null) + fConnector.load(fStore); + } + return fConnector; + } + + public boolean isInitialized() { + return fConnector!=null || fException!=null; + } + public void connect(ITerminalControl control) { + getConnectorImpl().connect(control); + } + public void disconnect() { + getConnectorImpl().disconnect(); + } + public OutputStream getTerminalToRemoteStream() { + return getConnectorImpl().getTerminalToRemoteStream(); + } + public String getSettingsSummary() { + if(fConnector!=null) + return getConnectorImpl().getSettingsSummary(); + else + return TerminalMessages.NotInitialized; + } + public boolean isLocalEcho() { + return getConnectorImpl().isLocalEcho(); + } + public void load(ISettingsStore store) { + if(fConnector==null) { + fStore=store; + } else { + getConnectorImpl().load(store); + } + } + @Override + public void setDefaultSettings() { + getConnectorImpl().setDefaultSettings(); + } + public void save(ISettingsStore store) { + // no need to save the settings: it cannot have changed + // because we are not initialized.... + if(fConnector!=null) + getConnectorImpl().save(store); + } + public void setTerminalSize(int newWidth, int newHeight) { + // we assume that setTerminalSize is called also after + // the terminal has been initialized. Else we would have to cache + // the values.... + if(fConnector!=null) { + fConnector.setTerminalSize(newWidth, newHeight); + } + } + public Object getAdapter(Class adapter) { + TerminalConnectorImpl connector=null; + if(isInitialized()) + connector=getConnectorImpl(); + // if we cannot create the connector then we cannot adapt... + if(connector!=null) { + // maybe the connector is adaptable + if(connector instanceof IAdaptable) { + Object result =((IAdaptable)connector).getAdapter(adapter); + // Not sure if the next block is needed.... + if(result==null) + //defer to the platform + result= Platform.getAdapterManager().getAdapter(connector, adapter); + if(result!=null) + return result; + } + // maybe the real adapter is what we need.... + if(adapter.isInstance(connector)) + return connector; + } + // maybe we have to be adapted.... + return Platform.getAdapterManager().getAdapter(this, adapter); + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/connector/TerminalToRemoteInjectionOutputStream.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/connector/TerminalToRemoteInjectionOutputStream.java new file mode 100644 index 00000000000..362306a4fb1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/connector/TerminalToRemoteInjectionOutputStream.java @@ -0,0 +1,171 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.connector; + +import java.io.ByteArrayOutputStream; +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noreference This class is not intended to be referenced by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * This class used to be package-protected. It is public only for access by the Unit Tests. + */ +public class TerminalToRemoteInjectionOutputStream extends FilterOutputStream { + /** + * This class handles bytes written to the {@link TerminalToRemoteInjectionOutputStream}. + */ + static abstract public class Interceptor { + protected OutputStream fOriginal; + /** + * @param original the injection into the original stream begins + * @throws IOException + */ + public void begin(OutputStream original) throws IOException { + fOriginal=original; + } + /** + * @param b a byte was written to the {@link TerminalToRemoteInjectionOutputStream}. + * @throws IOException + */ + public void write(int b) throws IOException { + } + /** + * @param b bytes written to the {@link TerminalToRemoteInjectionOutputStream}. + * @param off the start offset in the data. + * @param len the number of bytes to write. + * @throws IOException + */ + public void write(byte[] b, int off, int len) throws IOException { + } + /** + * The injection into the normal stream ends. + * @throws IOException + */ + public void close() throws IOException { + } + public void flush() { + } + } + static public class BufferInterceptor extends Interceptor { + private final ByteArrayOutputStream fBuffer=new ByteArrayOutputStream(); + public void close() throws IOException { + fOriginal.write(fBuffer.toByteArray()); + } + public void write(byte[] b, int off, int len) throws IOException { + fBuffer.write(b, off, len); + } + public void write(int b) throws IOException { + fBuffer.write(b); + } + } + private class TerminalFilterOutputStream extends OutputStream { + final private Object fLock=TerminalToRemoteInjectionOutputStream.this; + public void close() throws IOException { + synchronized(fLock) { + if(fInjection==this) { + flush(); + ungrabOutput(); + } + } + } + public void write(byte[] b, int off, int len) throws IOException { + synchronized(fLock) { + checkStream(); + out.write(b, off, len); + } + } + public void write(byte[] b) throws IOException { + synchronized(fLock) { + checkStream(); + out.write(b); + } + } + public void flush() throws IOException { + synchronized(fLock) { + checkStream(); + out.flush(); + } + } + public void write(int b) throws IOException { + synchronized(fLock) { + checkStream(); + out.write(b); + } + } + private void checkStream() throws IOException { + if(fInjection!=this) + throw new IOException("Stream is closed"); //$NON-NLS-1$ + } + } + private Interceptor fInterceptor; + private TerminalFilterOutputStream fInjection; + public TerminalToRemoteInjectionOutputStream(OutputStream out) { + super(out); + } + synchronized protected void ungrabOutput() throws IOException { + if(fInterceptor!=null) { + fInterceptor.close(); + fInterceptor=null; + fInjection=null; + } + } + /** + * There can only be one injection stream active at a time. You must call close on the + * returned output stream to end the injection. + * @param interceptor This is used handle bytes sent while the injection stream is active. + * @return a output stream that can be used to write to the decorated stream. + * @throws IOException + */ + public synchronized OutputStream grabOutput(Interceptor interceptor) throws IOException { + if(fInjection!=null) { + throw new IOException("Buffer in use"); //$NON-NLS-1$ + } + fInterceptor=interceptor; + fInterceptor.begin(out); + fInjection=new TerminalFilterOutputStream(); + return fInjection; + } + /** See {@link #grabOutput(TerminalToRemoteInjectionOutputStream.Interceptor)}. + * @return injection output stream + * @throws IOException + */ + public synchronized OutputStream grabOutput() throws IOException { + return grabOutput(new BufferInterceptor()); + } + synchronized public void close() throws IOException { + if(fInjection!=null) { + fInjection.close(); + } + super.close(); + } + synchronized public void flush() throws IOException { + if(fInterceptor!=null) + fInterceptor.flush(); + out.flush(); + } + synchronized public void write(byte[] b, int off, int len) throws IOException { + if(fInterceptor!=null) + fInterceptor.write(b, off, len); + else + out.write(b, off, len); + } + synchronized public void write(int b) throws IOException { + if(fInterceptor!=null) + fInterceptor.write(b); + else + out.write(b); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/CommandInputFieldWithHistory.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/CommandInputFieldWithHistory.java new file mode 100644 index 00000000000..0034ea648ba --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/CommandInputFieldWithHistory.java @@ -0,0 +1,324 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial implementation + * Michael Scharf (Wing River) - [211659] Add field assist to terminal input field + * Michael Scharf (Wing River) - [196447] The optional terminal input line should be resizeable + * Martin Oberhuber (Wind River) - [168197] Fix Terminal for CDC-1.1/Foundation-1.1 + * Michael Scharf (Wing River) - [236458] Fix 168197 lost the last entry + * Anton Leherbauer (Wind River) - [220971] The optional terminal input line has redraw problems when resizing + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.StringTokenizer; + +import org.eclipse.jface.fieldassist.IContentProposal; +import org.eclipse.jface.fieldassist.IContentProposalProvider; +import org.eclipse.jface.fieldassist.TextContentAdapter; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Sash; +import org.eclipse.swt.widgets.Text; +import org.eclipse.ui.fieldassist.ContentAssistCommandAdapter; + + + +/** + * Manages the Command History for the command line input + * of the terminal control. + *
  • + *
      Navigate with ARROW_UP,ARROW_DOWN,PAGE_UP,PAGE_DOWN + *
        ESC to cancel history editing + *
          History can be edited (by moving up and edit) but changes are + * not persistent (like in bash). + *
            If the same command is entered multiple times in a row, + * only one entry is kept in the history. + * + * + */ +public class CommandInputFieldWithHistory implements ICommandInputField { + private class FieldAssist implements IContentProposalProvider { + + public IContentProposal[] getProposals(String contents, int position) { + String prefix=contents.substring(0, position); + List result=new ArrayList(); + // show an entry only once + Set seen=new HashSet(); + for (Iterator iterator = fHistory.iterator(); iterator.hasNext();) { + String history = iterator.next(); + if(history.startsWith(prefix) && !seen.contains(history)) { + // the content is the rest of the history item + String content=history.substring(prefix.length()); + result.add(new Proposal(content,history)); + // don't add this proposal again + seen.add(history); + } + } + return result.toArray(new IContentProposal[result.size()]); + } + + } + private static class Proposal implements IContentProposal { + + private final String fContent; + private final String fLabel; + Proposal(String content, String label) { + fContent= content; + fLabel= label; + } + public String getContent() { + return fContent; + } + + public String getLabel() { + return fLabel; + } + + public String getDescription() { + return null; + } + + public int getCursorPosition() { + return fContent.length(); + } + } + + final List fHistory=new ArrayList(); + /** + * Keeps a modifiable history while in history editing mode + */ + List fEditedHistory; + /** + * The current position in the edit history + */ + private int fEditHistoryPos=0; + /** + * The limit of the history. + */ + private final int fMaxSize; + /** + * The input text field. + */ + private Text fInputField; + private Sash fSash; + private Composite fPanel; + public CommandInputFieldWithHistory(int maxHistorySize) { + fMaxSize=maxHistorySize; + } + /** + * Add a line to the history. + * @param line The line to be added to the history. + */ + protected void pushLine(String line) { + endHistoryMode(); + // anything to remember? + if(line==null || line.trim().length()==0) + return; + fHistory.add(0,line); + // ignore if the same as last + if(fHistory.size()>1 && line.equals(fHistory.get(1))) + fHistory.remove(0); + // limit the history size. + if(fHistory.size()>=fMaxSize) + fHistory.remove(fHistory.size()-1); + } + /** + * Sets the history + * @param history or null + */ + public void setHistory(String history) { + endHistoryMode(); + fHistory.clear(); + if(history==null) + return; + // add history entries separated by '\n' + // fHistory.addAll(Arrays.asList(history.split("\n"))); //$NON-NLS-1$ + // + StringTokenizer tok=new StringTokenizer(history,"\n"); //$NON-NLS-1$ + while(tok.hasMoreElements()) + fHistory.add((String) tok.nextElement()); + // + } + /** + * @return the current content of the history buffer and new line separated list + */ + public String getHistory() { + StringBuffer buff=new StringBuffer(); + boolean sep=false; + for (Iterator iterator = fHistory.iterator(); iterator.hasNext();) { + String line=iterator.next(); + if(line.length()>0) { + if(sep) + buff.append("\n"); //$NON-NLS-1$ + else + sep=true; + buff.append(line); + } + } + return buff.toString(); + } + /** + * @param currLine Line of text to be moved in history + * @param count (+1 or -1) for forward and backward movement. -1 goes back + * @return the new string to be displayed in the command line or null, + * if the limit is reached. + */ + public String move(String currLine, int count) { + if(!inHistoryMode()) { + fEditedHistory=new ArrayList(fHistory.size()+1); + fEditedHistory.add(currLine); + fEditedHistory.addAll(fHistory); + fEditHistoryPos=0; + } + fEditedHistory.set(fEditHistoryPos,currLine); + if(fEditHistoryPos+count>=fEditedHistory.size()) + return null; + if(fEditHistoryPos+count<0) + return null; + fEditHistoryPos+=count; + return (String) fEditedHistory.get(fEditHistoryPos); + } + private boolean inHistoryMode() { + return fEditedHistory!=null; + } + + /** + * Exit the history movements and go to position 0; + * @return the string to be shown in the command line + */ + protected String escape() { + if(!inHistoryMode()) + return null; + String line= (String) fEditedHistory.get(0); + endHistoryMode(); + return line; + } + /** + * End history editing + */ + private void endHistoryMode() { + fEditedHistory=null; + fEditHistoryPos=0; + } + public void createControl(final Composite parent,final ITerminalViewControl terminal) { +// fSash = new Sash(parent,SWT.HORIZONTAL|SWT.SMOOTH); + fSash = new Sash(parent,SWT.HORIZONTAL); + final GridData gd_sash = new GridData(SWT.FILL, SWT.CENTER, true, false); + gd_sash.heightHint=5; + fSash.setLayoutData(gd_sash); + fSash.addListener (SWT.Selection, new Listener () { + public void handleEvent (Event e) { + if (e.detail == SWT.DRAG) { + // don't redraw during drag, it causes paint errors - bug 220971 + return; + } + // no idea why this is needed + GridData gdata = (GridData) fInputField.getLayoutData(); + Rectangle sashRect = fSash.getBounds (); + Rectangle containerRect = parent.getClientArea (); + + int h=fInputField.getLineHeight(); + // make sure the input filed height is a multiple of the line height + gdata.heightHint = Math.max(((containerRect.height-e.y-sashRect.height)/h)*h,h); + // do not show less then one line + e.y=Math.min(e.y,containerRect.height-h); + fInputField.setLayoutData(gdata); + parent.layout(); + // else the content assist icon will be replicated + parent.redraw(); + } + }); + fPanel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginWidth = 0; layout.marginHeight = 0; layout.marginTop = 0; layout.marginBottom = 2; + fPanel.setLayout(layout); + fPanel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false)); + fInputField=new Text(fPanel, SWT.MULTI|SWT.BORDER|SWT.WRAP|SWT.V_SCROLL); + GridData data=new GridData(SWT.FILL, SWT.FILL, true, false); + boolean installDecoration=true; + if(installDecoration) { + // The ContentAssistCommandAdapter says: "The client is responsible for + // ensuring that adequate space is reserved for the decoration." + // TODO: what is the "adequate space"??? + data.horizontalIndent=6; + } + fInputField.setLayoutData(data); + fInputField.setFont(terminal.getFont()); + // Register field assist *before* the key listener. + // Else the ENTER key is sent *first* to the input field + // and then to the field assist popup. + // (https://bugs.eclipse.org/bugs/show_bug.cgi?id=211659) + new ContentAssistCommandAdapter( + fInputField, + new TextContentAdapter(), + new FieldAssist(), + null, + null, + installDecoration); + fInputField.addKeyListener(new KeyListener(){ + public void keyPressed(KeyEvent e) { + // if the field assist has handled the key already then + // ignore it (https://bugs.eclipse.org/bugs/show_bug.cgi?id=211659) + if(!e.doit) + return; + if(e.character==SWT.CR || e.character==SWT.LF) { + e.doit=false; + String line=fInputField.getText(); + if(!terminal.pasteString(line+'\r')) + return; + pushLine(line); + setCommand("");//$NON-NLS-1$ + } else if(e.keyCode==SWT.ARROW_UP || e.keyCode==SWT.PAGE_UP) { + e.doit=false; + setCommand(move(fInputField.getText(),1)); + } else if(e.keyCode==SWT.ARROW_DOWN || e.keyCode==SWT.PAGE_DOWN) { + e.doit=false; + setCommand(move(fInputField.getText(),-1)); + } else if(e.keyCode==SWT.ESC) { + e.doit=false; + setCommand(escape()); + } + } + private void setCommand(String line) { + if(line==null) + return; + fInputField.setText(line); + fInputField.setSelection(fInputField.getCharCount()); + } + public void keyReleased(KeyEvent e) { + } + }); + } + public void setFont(Font font) { + fInputField.setFont(font); + fInputField.getParent().layout(true); + } + public void dispose() { + fSash.dispose(); + fSash=null; + fPanel.dispose(); + fPanel=null; + fInputField.dispose(); + fInputField=null; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ICommandInputField.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ICommandInputField.java new file mode 100644 index 00000000000..2e31750195f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ICommandInputField.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.widgets.Composite; + +/** + * Interface to create a command input control. + * + */ +public interface ICommandInputField { + /** + * @param parent + * @param terminal + */ + void createControl(Composite parent, ITerminalViewControl terminal); + + void dispose(); + /** + * Sets the font of a control created with {@link #createControl(Composite, ITerminalViewControl)} + * @param control + * @param font the new text font + */ + void setFont(Font font); + +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalListener.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalListener.java new file mode 100644 index 00000000000..62d548c29a0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalListener.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +import org.eclipse.tm.internal.terminal.provisional.api.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/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalListener2.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalListener2.java new file mode 100644 index 00000000000..1166a99c929 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalListener2.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +/** + * Terminal listener allowing to listen to terminal selection changes. + * + * @since 4.1 + */ +public interface ITerminalListener2 extends ITerminalListener { + + /** + * selection has been changed internally e.g. select all + * clients might want to react on that + * NOTE: this does not include mouse selections + * those are handled in separate MouseListeners + * TODO should be unified + */ + void setTerminalSelectionChanged(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalMouseListener.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalMouseListener.java new file mode 100644 index 00000000000..1e07fb20069 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalMouseListener.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 CWI. All rights reserved. + * This program and the accompanying materials are made available under the terms + * of the Eclipse Public License 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Davy Landman (CWI) - [475267][api] Initial definition of interface + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; + +/** + * Terminal specific version of {@link org.eclipse.swt.events.MouseListener} + * @since 4.1 + */ +public interface ITerminalMouseListener { + /** + * Invoked when a double-click has happend inside the terminal control.
            + *
            + * Important: the event fires for every click, even outside the text region. + * @param terminalText a read-only view of the current terminal text + * @param button see {@link org.eclipse.swt.events.MouseEvent#button} for the meaning of the button values + */ + void mouseDoubleClick(ITerminalTextDataReadOnly terminalText, int line, int column, int button); + /** + * Invoked when a mouse button is pushed down inside the terminal control.
            + *
            + * Important: the event fires for every mouse down, even outside the text region. + * @param terminalText a read-only view of the current terminal text + * @param button see {@link org.eclipse.swt.events.MouseEvent#button} for the meaning of the button values + */ + void mouseDown(ITerminalTextDataReadOnly terminalText, int line, int column, int button); + /** + * Invoked when a mouse button is released inside the terminal control.
            + *
            + * Important: the event fires for every mouse up, even outside the text region. + * @param terminalText a read-only view of the current terminal text + * @param button see {@link org.eclipse.swt.events.MouseEvent#button} for the meaning of the button values + */ + void mouseUp(ITerminalTextDataReadOnly terminalText, int line, int column, int button); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java new file mode 100644 index 00000000000..08706167229 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/ITerminalViewControl.java @@ -0,0 +1,135 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [204796] Terminal should allow setting the encoding to use + * Martin Oberhuber (Wind River) - [265352][api] Allow setting fonts programmatically + * Davy Landman (CWI) - [475267][api] Allow custom mouse listeners + ******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +import java.io.UnsupportedEncodingException; + +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +/** + * @author Michael Scharf + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITerminalViewControl { + /** + * Set the encoding that the Terminal uses to decode byte streams into + * characters. + * + * @see ITerminalControl#setEncoding(String) + * @since org.eclipse.tm.terminal 2.0 + */ + void setEncoding(String encoding) throws UnsupportedEncodingException; + + /** + * Get the Terminal's current encoding. + * + * @return the current Encoding of the Terminal. + * @see ITerminalControl#getEncoding() + * @since org.eclipse.tm.terminal 2.0 + */ + String getEncoding(); + + boolean isEmpty(); + /** + * Sets the Terminal font + * @deprecated use {@link #setFont(String)} in order to support bold and italic variants of the given font + * @param font + */ + void setFont(Font font); + /** + * Sets the font for the Terminal, using a JFace symbolic font name, such + * that bold and italic variants can be leveraged. + * @since 3.2 + * @param fontName + */ + void setFont(String fontName); + void setInvertedColors(boolean invert); + Font getFont(); + /** + * @return the text control + */ + Control getControl(); + /** + * @return the root of all controls + */ + Control getRootControl(); + boolean isDisposed(); + void selectAll(); + void clearTerminal(); + void copy(); + void paste(); + String getSelection(); + TerminalState getState(); + Clipboard getClipboard(); + void disconnectTerminal(); + void disposeTerminal(); + String getSettingsSummary(); + ITerminalConnector[] getConnectors(); + void setFocus(); + ITerminalConnector getTerminalConnector(); + void setConnector(ITerminalConnector connector); + void connectTerminal(); + /** + * @param write a single character to terminal + */ + void sendKey(char arg0); + /** + * @param string write string to terminal + */ + public boolean pasteString(String string); + + boolean isConnected(); + + /** + * @param inputField null means no input field is shown + */ + void setCommandInputField(ICommandInputField inputField); + /** + * @return null or the current input field + */ + ICommandInputField getCommandInputField(); + + /** + * @return the maximum number of lines to display + * in the terminal view. -1 means unlimited. + */ + public int getBufferLineLimit(); + + /** + * @param bufferLineLimit the maximum number of lines to show + * in the terminal view. -1 means unlimited. + */ + public void setBufferLineLimit(int bufferLineLimit); + boolean isScrollLock(); + void setScrollLock(boolean on); + + /** + * @since 4.1 + */ + void addMouseListener(ITerminalMouseListener listener); + /** + * @since 4.1 + */ + void removeMouseListener(ITerminalMouseListener listener); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/TerminalViewControlFactory.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/TerminalViewControlFactory.java new file mode 100644 index 00000000000..42717a45731 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/TerminalViewControlFactory.java @@ -0,0 +1,44 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.internal.terminal.emulator.VT100TerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; + +public class TerminalViewControlFactory { + /** + * Instantiate a Terminal widget. + * @param target Callback for notifying the owner of Terminal state changes. + * @param wndParent The Window parent to embed the Terminal in. + * @param connectors Provided connectors. + */ + public static ITerminalViewControl makeControl(ITerminalListener target, Composite wndParent, ITerminalConnector[] connectors) { + return makeControl(target, wndParent, connectors, false); + } + + /** + * Instantiate a Terminal widget. + * @param target Callback for notifying the owner of Terminal state changes. + * @param wndParent The Window parent to embed the Terminal in. + * @param connectors Provided connectors. + * @param useCommonPrefs If true, the Terminal widget will pick up settings + * from the org.eclipse.tm.terminal.TerminalPreferencePage Preference page. + * Otherwise, clients need to maintain settings themselves. + * @since 3.2 + */ + public static ITerminalViewControl makeControl(ITerminalListener target, Composite wndParent, ITerminalConnector[] connectors, boolean useCommonPrefs) { + return new VT100TerminalControl(target, wndParent, connectors, useCommonPrefs); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/AbstractTerminalAction.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/AbstractTerminalAction.java new file mode 100644 index 00000000000..218044a07aa --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/AbstractTerminalAction.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - Adapted from TerminalAction + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.jface.action.Action; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin; + +public abstract class AbstractTerminalAction extends Action { + private final ITerminalViewControl fTarget; + + public AbstractTerminalAction(String strId) { + this(null, strId, 0); + } + + public AbstractTerminalAction(ITerminalViewControl target, + String strId) { + this(target, strId, 0); + } + + public AbstractTerminalAction(ITerminalViewControl target, + String strId, int style) { + super("", style); //$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) { + setupAction(strText, strToolTip, strImage, strEnabledImage, + strDisabledImage, bEnabled, TerminalPlugin.getDefault() + .getImageRegistry()); + } + + protected void setupAction(String strText, String strToolTip, + String strHoverImage, String strEnabledImage, + String strDisabledImage, boolean bEnabled, + ImageRegistry imageRegistry) { + setupAction(strText, strToolTip, imageRegistry + .getDescriptor(strHoverImage), imageRegistry + .getDescriptor(strEnabledImage), imageRegistry + .getDescriptor(strDisabledImage), bEnabled); + } + + protected void setupAction(String strText, String strToolTip, + ImageDescriptor hoverImage, ImageDescriptor enabledImage, + ImageDescriptor disabledImage, boolean bEnabled) { + setText(strText); + setToolTipText(strToolTip); + setEnabled(bEnabled); + if (enabledImage != null) { + setImageDescriptor(enabledImage); + } + if (disabledImage != null) { + setDisabledImageDescriptor(disabledImage); + } + if (hoverImage != null) { + setHoverImageDescriptor(hoverImage); + } + } + + /** + * Return the terminal instance on which the action should operate. + * + * @return the terminal instance on which the action should operate. + */ + protected ITerminalViewControl getTarget() { + return fTarget; + } + + /** + * Subclasses can update their action + * + * @param aboutToShow true before the menu is shown -- false when the menu + * gets hidden + */ + public void updateAction(boolean aboutToShow) { + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ActionMessages.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ActionMessages.java new file mode 100644 index 00000000000..80baa8a81fe --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ActionMessages.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.osgi.util.NLS; + +public class ActionMessages extends NLS { + static { + NLS.initializeMessages(ActionMessages.class.getName(), + ActionMessages.class); + } + + public static String COPY; + public static String CUT; + public static String PASTE; + public static String SELECTALL; + public static String CLEARALL; + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ActionMessages.properties b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ActionMessages.properties new file mode 100644 index 00000000000..ffc7d452c3a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ActionMessages.properties @@ -0,0 +1,27 @@ +############################################################################### +# Copyright (c) 2003, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Initial Contributors: +# The following Wind River employees contributed to the Terminal component +# that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, +# Helmut Haigermoser and Ted Williams. +# +# Contributors: +# Michael Scharf (Wind River) - split into core, view and connector plugins +# Martin Oberhuber (Wind River) - fixed copyright headers and beautified +# Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin +############################################################################### + +# NLS_MESSAGEFORMAT_NONE + +COPY = Copy +CUT = Cut +PASTE = Paste +SELECTALL = Select All +CLEARALL = Clear Terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ImageConsts.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ImageConsts.java new file mode 100644 index 00000000000..e44e7dfaa27 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/ImageConsts.java @@ -0,0 +1,33 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - extracted from TerminalConsts + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +public interface ImageConsts { + public final static String IMAGE_DIR_ROOT = "icons/"; //$NON-NLS-1$ + public final static String IMAGE_DIR_LOCALTOOL = IMAGE_DIR_ROOT + "clcl16/"; // basic colors - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_DLCL = IMAGE_DIR_ROOT + "dlcl16/"; // disabled - size 16x16 //$NON-NLS-1$ + public final static String IMAGE_DIR_ELCL = IMAGE_DIR_ROOT+ "elcl16/"; // enabled - size 16x16 //$NON-NLS-1$ + + public static final String IMAGE_CLCL_CLEAR_ALL = "ImageClclClearAll"; //$NON-NLS-1$ + + public static final String IMAGE_DLCL_CLEAR_ALL = "ImageDlclClearAll"; //$NON-NLS-1$ + + public static final String IMAGE_ELCL_CLEAR_ALL = "ImageElclClearAll"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionClearAll.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionClearAll.java new file mode 100644 index 00000000000..eb0e91ce181 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionClearAll.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + * Uwe Stieber (Wind River) - [260372] [terminal] Certain terminal actions are enabled if no target terminal control is available + ********************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; + +public class TerminalActionClearAll extends AbstractTerminalAction { + public TerminalActionClearAll() { + super(TerminalActionClearAll.class.getName()); + + setupAction(ActionMessages.CLEARALL, ActionMessages.CLEARALL, + ImageConsts.IMAGE_CLCL_CLEAR_ALL, + ImageConsts.IMAGE_ELCL_CLEAR_ALL, + ImageConsts.IMAGE_DLCL_CLEAR_ALL, false); + } + + public TerminalActionClearAll(ITerminalViewControl target) { + super(target, TerminalActionClearAll.class.getName()); + + setupAction(ActionMessages.CLEARALL, ActionMessages.CLEARALL, + ImageConsts.IMAGE_CLCL_CLEAR_ALL, + ImageConsts.IMAGE_ELCL_CLEAR_ALL, + ImageConsts.IMAGE_DLCL_CLEAR_ALL, false); + } + + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + target.clearTerminal(); + } + } + + public void updateAction(boolean aboutToShow) { + ITerminalViewControl target = getTarget(); + setEnabled(target != null && !target.isEmpty()); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionCopy.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionCopy.java new file mode 100644 index 00000000000..375accd6c0b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionCopy.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + * Uwe Stieber (Wind River) - [260372] [terminal] Certain terminal actions are enabled if no target terminal control is available + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +public class TerminalActionCopy extends AbstractTerminalAction { + public TerminalActionCopy() { + super(TerminalActionCopy.class.getName()); + setActionDefinitionId("org.eclipse.tm.terminal.copy"); //$NON-NLS-1$ + ISharedImages si = PlatformUI.getWorkbench().getSharedImages(); + setupAction(ActionMessages.COPY, ActionMessages.COPY, si + .getImageDescriptor(ISharedImages.IMG_TOOL_COPY), si + .getImageDescriptor(ISharedImages.IMG_TOOL_COPY), si + .getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED), true); + } + + public TerminalActionCopy(ITerminalViewControl target) { + super(target, TerminalActionCopy.class.getName()); + setActionDefinitionId("org.eclipse.tm.terminal.copy"); //$NON-NLS-1$ + ISharedImages si = PlatformUI.getWorkbench().getSharedImages(); + setupAction(ActionMessages.COPY, ActionMessages.COPY, si + .getImageDescriptor(ISharedImages.IMG_TOOL_COPY), si + .getImageDescriptor(ISharedImages.IMG_TOOL_COPY), si + .getImageDescriptor(ISharedImages.IMG_TOOL_COPY_DISABLED), true); + } + + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + String selection = target.getSelection(); + + if (!selection.equals("")) {//$NON-NLS-1$ + target.copy(); + } else { + target.sendKey('\u0003'); + } + } + } + + public void updateAction(boolean aboutToShow) { + ITerminalViewControl target = getTarget(); + boolean bEnabled = target != null; + if (aboutToShow && bEnabled) { + bEnabled = target.getSelection().length() > 0; + } + setEnabled(bEnabled); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionCut.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionCut.java new file mode 100644 index 00000000000..d35479dd174 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionCut.java @@ -0,0 +1,56 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Uwe Stieber (Wind River) - [260372] [terminal] Certain terminal actions are enabled if no target terminal control is available + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +public class TerminalActionCut extends AbstractTerminalAction { + public TerminalActionCut() { + super(TerminalActionCut.class.getName()); + ISharedImages si = PlatformUI.getWorkbench().getSharedImages(); + setupAction(ActionMessages.CUT, ActionMessages.CUT, si + .getImageDescriptor(ISharedImages.IMG_TOOL_CUT), si + .getImageDescriptor(ISharedImages.IMG_TOOL_CUT), si + .getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED), true); + } + + public TerminalActionCut(ITerminalViewControl target) { + super(target, TerminalActionCut.class.getName()); + ISharedImages si = PlatformUI.getWorkbench().getSharedImages(); + setupAction(ActionMessages.CUT, ActionMessages.CUT, si + .getImageDescriptor(ISharedImages.IMG_TOOL_CUT), si + .getImageDescriptor(ISharedImages.IMG_TOOL_CUT), si + .getImageDescriptor(ISharedImages.IMG_TOOL_CUT_DISABLED), true); + } + + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + target.sendKey('\u0018'); + } + } + + public void updateAction(boolean aboutToShow) { + // Cut is always disabled + setEnabled(false); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionPaste.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionPaste.java new file mode 100644 index 00000000000..af13acb3964 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionPaste.java @@ -0,0 +1,71 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + * Uwe Stieber (Wind River) - [260372] [terminal] Certain terminal actions are enabled if no target terminal control is available + * Uwe Stieber (Wind River) - [294719] [terminal] SWT Widget disposed in TerminalActionPaste + * Martin Oberhuber (Wind River) - [296212] Cannot paste text into terminal on some Linux hosts + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.PlatformUI; + +public class TerminalActionPaste extends AbstractTerminalAction { + public TerminalActionPaste() { + super(TerminalActionPaste.class.getName()); + setActionDefinitionId("org.eclipse.tm.terminal.paste"); //$NON-NLS-1$ + ISharedImages si = PlatformUI.getWorkbench().getSharedImages(); + setupAction(ActionMessages.PASTE, ActionMessages.PASTE, + si.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE), + si.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE), + si.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED), + false); + } + + public TerminalActionPaste(ITerminalViewControl target) { + super(target, TerminalActionPaste.class.getName()); + setActionDefinitionId("org.eclipse.tm.terminal.paste"); //$NON-NLS-1$ + ISharedImages si = PlatformUI.getWorkbench().getSharedImages(); + setupAction(ActionMessages.PASTE, ActionMessages.PASTE, + si.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE), + si.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE), + si.getImageDescriptor(ISharedImages.IMG_TOOL_PASTE_DISABLED), + false); + } + + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + target.paste(); + } + } + + public void updateAction(boolean aboutToShow) { + ITerminalViewControl target = getTarget(); + boolean bEnabled = target != null && target.getClipboard() != null && !target.getClipboard().isDisposed(); + if (bEnabled) { + String strText = (String) target.getClipboard().getContents( + TextTransfer.getInstance()); + bEnabled = ((strText != null) && (!strText.equals("")) && (target.getState() == TerminalState.CONNECTED));//$NON-NLS-1$ + } + setEnabled(bEnabled); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionSelectAll.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionSelectAll.java new file mode 100644 index 00000000000..b2f0057e3d3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/actions/TerminalActionSelectAll.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2004, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + * Uwe Stieber (Wind River) - [260372] [terminal] Certain terminal actions are enabled if no target terminal control is available + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.actions; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; + +public class TerminalActionSelectAll extends AbstractTerminalAction { + public TerminalActionSelectAll() { + super(TerminalActionSelectAll.class.getName()); + + setupAction(ActionMessages.SELECTALL, ActionMessages.SELECTALL, + (ImageDescriptor) null, null, null, false); + } + + public TerminalActionSelectAll(ITerminalViewControl target) { + super(target, TerminalActionSelectAll.class.getName()); + + setupAction(ActionMessages.SELECTALL, ActionMessages.SELECTALL, + (ImageDescriptor) null, null, null, false); + } + + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + target.selectAll(); + } + } + + public void updateAction(boolean aboutToShow) { + ITerminalViewControl target = getTarget(); + setEnabled(target != null && !target.isEmpty()); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/ITerminalControlForText.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/ITerminalControlForText.java new file mode 100644 index 00000000000..0bbd0096fbb --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/ITerminalControlForText.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anton Leherbauer (Wind River) - [458398] Add support for normal/application cursor keys mode + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.impl; + +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +/** + * need a better name! + * @author Michael Scharf + * + */ +public interface ITerminalControlForText { + + TerminalState getState(); + void setState(TerminalState state); + void setTerminalTitle(String title); + + ITerminalConnector getTerminalConnector(); + + OutputStream getOutputStream(); + + /** + * Enable/disable Application Cursor Keys mode (DECCKM) + * @param enable + */ + void enableApplicationCursorKeys(boolean enable); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalMessages.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalMessages.java new file mode 100644 index 00000000000..56b3d1b3511 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalMessages.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.impl; + +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 static String CannotConnectTo; + public static String NotInitialized; + + //Preference Page + public static String INVERT_COLORS; + public static String BUFFERLINES; + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalMessages.properties b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalMessages.properties new file mode 100644 index 00000000000..93ee9767472 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalMessages.properties @@ -0,0 +1,30 @@ +############################################################################### +# Copyright (c) 2003, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Initial Contributors: +# The following Wind River employees contributed to the Terminal component +# that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, +# Helmut Haigermoser and Ted Williams. +# +# Contributors: +# Michael Scharf (Wind River) - split into core, view and connector plugins +# Martin Oberhuber (Wind River) - fixed copyright headers and beautified +# Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget +############################################################################### + +# NLS_MESSAGEFORMAT_VAR + +TerminalError = Terminal Error +SocketError = Socket Error +IOError = IO Error +CannotConnectTo = Cannot initialize {0}:\n{1} +NotInitialized = Not Initialized + +INVERT_COLORS = Invert terminal colors +BUFFERLINES = Terminal buffer lines: diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java new file mode 100644 index 00000000000..c566aaf61c6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/control/impl/TerminalPlugin.java @@ -0,0 +1,94 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Anna Dushistova (MontaVista) - [227537] moved actions from terminal.view to terminal plugin + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.control.impl; + +import java.net.MalformedURLException; +import java.net.URL; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.tm.internal.terminal.control.actions.ImageConsts; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.BundleContext; + +public class TerminalPlugin extends AbstractUIPlugin { + private static TerminalPlugin plugin; + public static final String PLUGIN_ID = "org.eclipse.tm.terminal.control"; //$NON-NLS-1$ + public static final String HELP_VIEW = PLUGIN_ID + ".terminal_view"; //$NON-NLS-1$ + + /** + * The constructor. + */ + public TerminalPlugin() { + } + /** + * Returns the shared instance. + */ + public static TerminalPlugin getDefault() { + return plugin; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + plugin = null; + super.stop(context); + } + + public static boolean isOptionEnabled(String strOption) { + String strEnabled = Platform.getDebugOption(strOption); + if (strEnabled == null) + return false; + + return new Boolean(strEnabled).booleanValue(); + } + + @Override + protected void initializeImageRegistry(ImageRegistry imageRegistry) { + try { + // Local toolbars + putImageInRegistry(imageRegistry, ImageConsts.IMAGE_CLCL_CLEAR_ALL, ImageConsts.IMAGE_DIR_LOCALTOOL + "clear_co.gif"); //$NON-NLS-1$ + // Enabled local toolbars + putImageInRegistry(imageRegistry, ImageConsts.IMAGE_ELCL_CLEAR_ALL, ImageConsts.IMAGE_DIR_ELCL + "clear_co.gif"); //$NON-NLS-1$ + // Disabled local toolbars + putImageInRegistry(imageRegistry, ImageConsts.IMAGE_DLCL_CLEAR_ALL, ImageConsts.IMAGE_DIR_DLCL + "clear_co.gif"); //$NON-NLS-1$ + } catch (MalformedURLException malformedURLException) { + malformedURLException.printStackTrace(); + } + } + + protected void putImageInRegistry(ImageRegistry imageRegistry, String strKey, String relativePath) throws MalformedURLException { + URL url = TerminalPlugin.getDefault().getBundle().getEntry(relativePath); + ImageDescriptor imageDescriptor = ImageDescriptor.createFromURL(url); + imageRegistry.put(strKey, imageDescriptor); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/EditActionAccelerators.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/EditActionAccelerators.java new file mode 100644 index 00000000000..6f5f5f2966f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/EditActionAccelerators.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2013, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + *******************************************************************************/ + +package org.eclipse.tm.internal.terminal.emulator; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.bindings.TriggerSequence; +import org.eclipse.jface.bindings.keys.KeySequence; +import org.eclipse.jface.bindings.keys.KeyStroke; +import org.eclipse.jface.bindings.keys.SWTKeySupport; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.keys.IBindingService; + +class EditActionAccelerators { + private static final String COPY_COMMAND_ID = "org.eclipse.tm.terminal.copy"; //$NON-NLS-1$ + private static final String PASTE_COMMAND_ID = "org.eclipse.tm.terminal.paste"; //$NON-NLS-1$ + + private final Map commandIdsByAccelerator = new HashMap(); + + private void load() { + addAccelerator(COPY_COMMAND_ID); + addAccelerator(PASTE_COMMAND_ID); + } + + private void addAccelerator(String commandId) { + TriggerSequence[] bindings = bindingsFor(commandId); + for (int i=0; i + * + * 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). + *

            + */ + void appendString(String buffer); + + /** + * Process a newline (Control-J) character. A newline (NL) character just + * moves the cursor to the same column on the next line, creating new lines + * when the cursor reaches the bottom edge of the terminal. This is + * counter-intuitive, especially to UNIX programmers who are taught that + * writing a single NL to a terminal is sufficient to move the cursor to the + * first column of the next line, as if a carriage return (CR) and a NL were + * written. + *

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

            + */ + void processNewline(); + + /** + * This method returns the relative line number of the line containing the + * cursor. The returned line number is relative to the topmost visible line, + * which has relative line number 0. + * + * @return The relative line number of the line containing the cursor. + */ + int getCursorLine(); + + int getCursorColumn(); + + /** + * This method moves the cursor to the specified line and column. Parameter + * 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. + */ + void setCursor(int targetLine, int targetColumn); + + void setCursorColumn(int targetColumn); + + void setCursorLine(int targetLine); + + int getLines(); + + int getColumns(); + + /** + * Enables VT100 line wrapping mode (default is off). + * This corresponds to the VT100 'eat_newline_glitch' terminal capability. + * If enabled, writing to the rightmost column does not cause + * an immediate wrap to the next line. Instead the line wrap occurs on the + * next output character. + * + * @param enable whether to enable or disable VT100 line wrapping mode + */ + void setVT100LineWrapping(boolean enable); + + /** + * @return whether VT100 line wrapping mode is enabled + */ + boolean isVT100LineWrapping(); + + /** + * Enables/disables insert mode (IRM). + * + * @param enable whether to enable insert mode + */ + void setInsertMode(boolean enable); + + /** + * Set scrolling region. Negative values reset the scroll region. + * + * @param top top line of scroll region + * @param bottom bottom line of scroll region + */ + void setScrollRegion(int top, int bottom); + + /** + * Scroll text upwards. + * + * @param lines number of lines to scroll + */ + void scrollUp(int lines); + + /** + * Scroll text downwards. + * + * @param lines number of lines to scroll + */ + void scrollDown(int lines); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/LoggingOutputStream.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/LoggingOutputStream.java new file mode 100644 index 00000000000..e291b9e5345 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/LoggingOutputStream.java @@ -0,0 +1,48 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.Logger; + +public class LoggingOutputStream extends FilterOutputStream { + + public LoggingOutputStream(OutputStream out) { + super(out); + } + + public void write(byte[] b, int off, int len) throws IOException { + if(Logger.isLogEnabled()) + Logger.log("Received " + len + " bytes: '" + //$NON-NLS-1$ //$NON-NLS-2$ + Logger.encode(new String(b, 0, len)) + "'"); //$NON-NLS-1$ + + // we cannot call super.write, because this would call our write + // which logs character by character..... + //super.write(b, off, len); + if ((off | len | (b.length - (len + off)) | (off + len)) < 0) + throw new IndexOutOfBoundsException(); + + for (int i = 0 ; i < len ; i++) { + super.write(b[off + i]); + } + } + + public void write(int b) throws IOException { + if(Logger.isLogEnabled()) + Logger.log("Received " + 1 + " bytes: '" + //$NON-NLS-1$ //$NON-NLS-2$ + Logger.encode(new String(new byte[]{(byte)b}, 0, 1)) + "'"); //$NON-NLS-1$ + super.write(b); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java new file mode 100644 index 00000000000..92d357f80d2 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100BackendTraceDecorator.java @@ -0,0 +1,176 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import java.io.PrintStream; + +import org.eclipse.tm.terminal.model.Style; + +public class VT100BackendTraceDecorator implements IVT100EmulatorBackend { + final IVT100EmulatorBackend fBackend; + final PrintStream fWriter; + public VT100BackendTraceDecorator(IVT100EmulatorBackend backend, PrintStream out) { + fBackend = backend; + fWriter=out; + } + + public void appendString(String buffer) { + fWriter.println("appendString(\""+buffer+"\")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.appendString(buffer); + } + + public void clearAll() { + fWriter.println("clearAll()"); //$NON-NLS-1$ + fBackend.clearAll(); + } + + public void deleteCharacters(int n) { + fWriter.println("deleteCharacters("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.deleteCharacters(n); + } + + public void deleteLines(int n) { + fWriter.println("deleteLines("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.deleteLines(n); + } + + public void eraseAll() { + fWriter.println("eraseAll()"); //$NON-NLS-1$ + fBackend.eraseAll(); + } + + public void eraseLine() { + fWriter.println("eraseLine()"); //$NON-NLS-1$ + fBackend.eraseLine(); + } + + public void eraseLineToCursor() { + fWriter.println("eraseLineToCursor()"); //$NON-NLS-1$ + fBackend.eraseLineToCursor(); + } + + public void eraseLineToEnd() { + fWriter.println("eraseLineToEnd()"); //$NON-NLS-1$ + fBackend.eraseLineToEnd(); + } + + public void eraseToCursor() { + fWriter.println("eraseToCursor()"); //$NON-NLS-1$ + fBackend.eraseToCursor(); + } + + public void eraseToEndOfScreen() { + fWriter.println("eraseToEndOfScreen()"); //$NON-NLS-1$ + fBackend.eraseToEndOfScreen(); + } + + public int getColumns() { + return fBackend.getColumns(); + } + + public int getCursorColumn() { + return fBackend.getCursorColumn(); + } + + public int getCursorLine() { + return fBackend.getCursorLine(); + } + + public Style getDefaultStyle() { + return fBackend.getDefaultStyle(); + } + + public int getLines() { + return fBackend.getLines(); + } + + public Style getStyle() { + return fBackend.getStyle(); + } + + public void insertCharacters(int charactersToInsert) { + fWriter.println("insertCharacters("+charactersToInsert+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.insertCharacters(charactersToInsert); + } + + public void insertLines(int n) { + fWriter.println("insertLines("+n+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.insertLines(n); + } + + public void processNewline() { + fWriter.println("processNewline()"); //$NON-NLS-1$ + fBackend.processNewline(); + } + + public void setCursor(int targetLine, int targetColumn) { + fWriter.println("setCursor("+targetLine+", "+targetColumn+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + fBackend.setCursor(targetLine, targetColumn); + } + + public void setCursorColumn(int targetColumn) { + fWriter.println("setCursorColumn("+targetColumn+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setCursorColumn(targetColumn); + } + + public void setCursorLine(int targetLine) { + fWriter.println("setCursorLine("+targetLine+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setCursorLine(targetLine); + } + + public void setDefaultStyle(Style defaultStyle) { + fWriter.println("setDefaultStyle("+defaultStyle+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setDefaultStyle(defaultStyle); + } + + public void setDimensions(int lines, int cols) { + fWriter.println("setDimensions("+lines+","+cols+")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + fBackend.setDimensions(lines, cols); + } + + public void setStyle(Style style) { + fWriter.println("setStyle("+style+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setStyle(style); + } + + public void setVT100LineWrapping(boolean enable) { + fWriter.println("setVT100LineWrapping("+enable+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setVT100LineWrapping(enable); + } + + public boolean isVT100LineWrapping() { + return fBackend.isVT100LineWrapping(); + } + + public void setInsertMode(boolean enable) { + fWriter.println("setInsertMode("+enable+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setInsertMode(enable); + } + + public void setScrollRegion(int top, int bottom) { + fWriter.println("setScrollRegion("+top+','+bottom+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.setScrollRegion(top, bottom); + } + + public void scrollUp(int lines) { + fWriter.println("scrollUp("+lines+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.scrollUp(lines); + } + + public void scrollDown(int lines) { + fWriter.println("scrollDown("+lines+")"); //$NON-NLS-1$ //$NON-NLS-2$ + fBackend.scrollDown(lines); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java new file mode 100644 index 00000000000..cc3b76424c9 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100Emulator.java @@ -0,0 +1,1398 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Michael Scharf (Wind River) - [209746] There are cases where some colors not displayed correctly + * Martin Oberhuber (Wind River) - [168197] Fix Terminal for CDC-1.1/Foundation-1.1 + * Michael Scharf (Wind River) - [262996] get rid of TerminalState.OPENED + * Martin Oberhuber (Wind River) - [334969] Fix multi-command SGR sequence + * Kris De Volder (VMWare) - [392107] Switched interpretation for ESC[0K and ESC[1K sequences + * Martin Oberhuber (Wind River) - [401386] Regression: No header on top due to incorrect ESC[K interpretation + * Martin Oberhuber (Wind River) - [401480] Handle ESC[39;49m and ESC[G + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458398] Add support for normal/application cursor keys mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import java.io.IOException; +import java.io.Reader; + +import org.eclipse.swt.events.ControlEvent; +import org.eclipse.swt.events.ControlListener; +import org.eclipse.tm.internal.terminal.control.impl.ITerminalControlForText; +import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.Style; + +/** + * 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 VT100Emulator implements ControlListener { + /** This is a character processing state: Initial state. */ + private static final int ANSISTATE_INITIAL = 0; + + /** This is a character processing state: We've seen an escape character. */ + private 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. + */ + private 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. + */ + private static final int ANSISTATE_EXPECTING_OS_COMMAND = 3; + + /** + * This is a character processing state: We've seen a '[?' after an escape + * character. Expecting a parameter character or a command character next. + */ + private static final int ANSISTATE_EXPECTING_DEC_PRIVATE_COMMAND = 4; + + /** + * This is a character processing state: We've seen one of ()*+-./ after an escape + * character. Expecting a character set designation character. + */ + private static final int ANSISTATE_EXPECTING_CHARSET_DESIGNATION = 5; + + + /** + * This field holds the current state of the Finite TerminalState Automaton (FSA) + * that recognizes ANSI escape sequences. + * + * @see #processNewText() + */ + private int ansiState = ANSISTATE_INITIAL; + + /** + * This field holds a reference to the {@link TerminalControl} object that + * instantiates this class. + */ + private final ITerminalControlForText terminal; + + /** + * This field holds a reference to the StyledText widget that is used to + * display text to the user. + */ + final private IVT100EmulatorBackend text; + /** + * This field hold the saved absolute line number of the cursor when + * processing the "ESC 7" and "ESC 8" command sequences. + */ + private int savedCursorLine = 0; + + /** + * This field hold the saved column number of the cursor when processing the + * "ESC 7" and "ESC 8" command sequences. + */ + private 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". + */ + private final StringBuffer[] ansiParameters = new StringBuffer[16]; + + /** + * This field holds the OS-specific command found in an escape sequence of + * the form "\e]...\u0007". + */ + private final StringBuffer ansiOsCommand = new StringBuffer(128); + + /** + * This field holds the index of the next unused element of the array stored + * in field {@link #ansiParameters}. + */ + private int nextAnsiParameter = 0; + + Reader fReader; + + boolean fCrAfterNewLine; + /** + * The constructor. + */ + public VT100Emulator(ITerminalTextData data, ITerminalControlForText terminal, Reader reader) { + super(); + + Logger.log("entered"); //$NON-NLS-1$ + + this.terminal = terminal; + + for (int i = 0; i < ansiParameters.length; ++i) { + ansiParameters[i] = new StringBuffer(); + } + setInputStreamReader(reader); + if(TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_VT100BACKEND)) + text=new VT100BackendTraceDecorator(new VT100EmulatorBackend(data),System.out); + else + text=new VT100EmulatorBackend(data); + +// text.setDimensions(24, 80); + Style style=Style.getStyle("BLACK", "WHITE"); //$NON-NLS-1$ //$NON-NLS-2$ + text.setDefaultStyle(style); + text.setStyle(style); + } + + /** + * Set the reader that this Terminal gets its input from. + * + * The reader can be changed while the Terminal is running, but a change of + * the reader likely loses some characters which have not yet been fully + * read. Changing the reader can be done in order to change the selected + * Encoding, though. This is typically done when the Terminal is + * constructed, i.e. before it really starts operation; or, when the user + * manually selects a different encoding and thus doesn't care about losing + * old characters. + * + * @param reader the new Reader + */ + public void setInputStreamReader(Reader reader) { + fReader = reader; + } + + public void setDimensions(int lines,int cols) { + text.setDimensions(lines, cols); + ITerminalConnector telnetConnection = getConnector(); + if (telnetConnection != null) { + telnetConnection.setTerminalSize(text.getColumns(), text.getLines()); + } + + } + + /** + * This method performs clean up when this VT100Emulator object is no longer + * needed. After calling this method, no other method on this object should + * be called. + */ + public void 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. + */ + public void controlResized(ControlEvent event) { + Logger.log("entered"); //$NON-NLS-1$ + adjustTerminalDimensions(); + } + + /** + * This method erases all text from the Terminal view. + */ + public void clearTerminal() { + Logger.log("entered"); //$NON-NLS-1$ + text.clearAll(); + } + + /** + * 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. + */ + public void fontChanged() { + Logger.log("entered"); //$NON-NLS-1$ + + if (text != null) + adjustTerminalDimensions(); + } +// /** +// * This method executes in the Display thread to process data received from +// * the remote host by class {@link org.eclipse.tm.internal.terminal.telnet.TelnetConnection} and +// * other implementors of {@link ITerminalConnector}, like the +// * SerialPortHandler. +// *

            +// * These connectors write text to the terminal's buffer through +// * {@link TerminalControl#writeToTerminal(String)} and then have +// * this run method executed in the display thread. 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 void processText() { + try { + // 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? + + try { + processNewText(); + } catch (IOException e) { + Logger.logException(e); + } + + } catch (Exception ex) { + Logger.logException(ex); + } + } + /** + * This method scans the newly received text, processing ANSI control + * characters and escape sequences and displaying normal text. + * @throws IOException + */ + private void processNewText() throws IOException { + Logger.log("entered"); //$NON-NLS-1$ + + + // Scan the newly received text. + + while (hasNextChar()) { + char character = getNextChar(); + + 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) + if(fCrAfterNewLine) + processCarriageReturn(); // Carriage Return (Control-M) + break; + + case '\r': + processCarriageReturn(); // Carriage Return (Control-M) + break; + + case '\u001b': + ansiState = ANSISTATE_ESCAPE; // Escape. + break; + + default: + processNonControlCharacters(character); + 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 ')': + case '(': + case '*': + case '+': + case '-': + case '.': + case '/': + ansiState = ANSISTATE_EXPECTING_CHARSET_DESIGNATION; + break; + + case '7': + // Save cursor position and character attributes + + ansiState = ANSISTATE_INITIAL; + savedCursorLine = relativeCursorLine(); + savedCursorColumn = getCursorColumn(); + break; + + case '8': + // Restore cursor and attributes to previously saved + // position + + ansiState = ANSISTATE_INITIAL; + moveCursor(savedCursorLine, savedCursorColumn); + break; + + case 'c': + // Reset the terminal + ansiState = ANSISTATE_INITIAL; + resetTerminal(); + 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: + if (character == '?') { + ansiState = ANSISTATE_EXPECTING_DEC_PRIVATE_COMMAND; + break; + } + + // 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; + + case ANSISTATE_EXPECTING_DEC_PRIVATE_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; + processDecPrivateCommandCharacter(character); + } else { + processAnsiParameterCharacter(character); + } + break; + + case ANSISTATE_EXPECTING_CHARSET_DESIGNATION: + if (character != '%') + ansiState = ANSISTATE_INITIAL; + // Character set designation commands are ignored + 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; + } + } + } + private void resetTerminal() { + text.eraseAll(); + text.setCursor(0, 0); + text.setStyle(text.getDefaultStyle()); + text.setScrollRegion(-1, -1); + text.setInsertMode(false); + terminal.enableApplicationCursorKeys(false); + } + /** + * 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. + */ + private 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. + *

            + */ + private 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? + + 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 'd': + // Line Position Absolute [row] (default = [1,column]) (VPA). + 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 'h': + // Reset Mode. + 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 'l': + // Set Mode. + 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 'r': + // Set Scrolling Region. + processAnsiCommand_r(); + break; + + case 'S': + // Scroll up. + processAnsiCommand_S(); + break; + + case 'T': + // Scroll down. + processAnsiCommand_T(); + 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 dispatches control to various processing methods based on the + * command character found in the most recently received DEC private mode escape + * sequence. This method only handles command characters that follow the + * control sequence CSI ? + */ + private void processDecPrivateCommandCharacter(char commandCharacter) { + switch (commandCharacter) { + case 'h': + // DEC Private Mode Set (DECSET) + processDecPrivateCommand_h(); + break; + + case 'l': + // DEC Private Mode Reset (DECRST) + processDecPrivateCommand_l(); + break; + + default: + Logger.log("Ignoring unsupported DEC private command character: '" + //$NON-NLS-1$ + commandCharacter + "'"); //$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 the line. + */ + private void processAnsiCommand_atsign() { + int charactersToInsert = getAnsiParameter(0); + text.insertCharacters(charactersToInsert); + } + + /** + * This method moves the cursor up by the number of lines specified by the + * escape sequence parameter (default 1). + */ + private 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). + */ + private 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). + */ + private 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). + */ + private void processAnsiCommand_D() { + moveCursorBackward(getAnsiParameter(0)); + } + + /** + * This method moves the cursor to a specific row. + */ + private void processAnsiCommand_d() { + // Line Position Absolute [row] (default = [1,column]) (VPA). + text.setCursorLine(getAnsiParameter(0) - 1); + } + + /** + * This method moves the cursor to the first column of the Nth next line, + * where N is specified by the ANSI parameter (default 1). + */ + private 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). + */ + private 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). + */ + private void processAnsiCommand_G() { + moveCursor(relativeCursorLine(), getAnsiParameter(0) - 1); + } + + /** + * This method sets the cursor to a position specified by the escape + * sequence parameters (default is the upper left corner of the screen). + */ + private void processAnsiCommand_H() { + moveCursor(getAnsiParameter(0) - 1, getAnsiParameter(1) - 1); + } + + /** + * This method sets terminal modes. + */ + private void processAnsiCommand_h() { + if (getAnsiParameter(0) == 4) { + // set insert mode + text.setInsertMode(true); + } + } + + /** + * This method deletes some (or all) of the text on the screen without + * moving the cursor. + */ + private void processAnsiCommand_J() { + int ansiParameter; + + if (ansiParameters[0].length() == 0) + ansiParameter = 0; + else + ansiParameter = getAnsiParameter(0); + + switch (ansiParameter) { + case 0: + text.eraseToEndOfScreen(); + break; + + case 1: + // Erase from beginning to current position (inclusive). + text.eraseToCursor(); + break; + + case 2: + // Erase entire display. + + text.eraseAll(); + 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. + */ + private void processAnsiCommand_K() { + //Bug 401386: missing parameter must be interpreted as 0, and not 1 like most other defaults. + int ansiParameter = 0; + if (ansiParameters[0].length() > 0) + ansiParameter = getAnsiParameter(0); + + switch (ansiParameter) { + case 0: + // Erase from current position to end (inclusive). + text.eraseLineToEnd(); + break; + + case 1: + // Erase from beginning to current position (inclusive). + text.eraseLineToCursor(); + break; + + case 2: + // Erase entire line. + text.eraseLine(); + break; + + default: + Logger.log("Unexpected K-command parameter: " + ansiParameter); //$NON-NLS-1$ + break; + } + } + + /** + * Insert one or more blank lines. The current line of text moves down. Text + * that falls off the bottom of the screen is deleted. + */ + private void processAnsiCommand_L() { + text.insertLines(getAnsiParameter(0)); + } + + /** + * This method resets terminal modes. + */ + private void processAnsiCommand_l() { + if (getAnsiParameter(0) == 4) { + // reset insert mode + text.setInsertMode(false); + } + } + + /** + * Delete one or more lines of text. Any lines below the deleted lines move + * up, which we implement by appending newlines to the end of the text. + */ + private void processAnsiCommand_M() { + text.deleteLines(getAnsiParameter(0)); + } + + /** + * This method sets a new graphics rendition mode, such as + * foreground/background color, bold/normal text, and reverse video. + */ + private 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'); + } + Style style=text.getStyle(); + // 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. + style = text.getDefaultStyle(); + break; + + case 1: + style = style.setBold(true); + break; + + case 4: + style = style.setUnderline(true); + break; + + case 5: + style = style.setBlink(true); + break; + + case 7: + style = style.setReverse(true); + break; + + case 10: // Set primary font. Ignored. + break; + + case 21: + case 22: + style = style.setBold(false); + break; + + case 24: + style = style.setUnderline(false); + break; + + case 25: + style = style.setBlink(false); + break; + + case 27: + style = style.setReverse(false); + break; + + case 30: + style = style.setForground("BLACK"); //$NON-NLS-1$ + break; + + case 31: + style = style.setForground("RED"); //$NON-NLS-1$ + break; + + case 32: + style = style.setForground("GREEN"); //$NON-NLS-1$ + break; + + case 33: + style = style.setForground("YELLOW"); //$NON-NLS-1$ + break; + + case 34: + style = style.setForground("BLUE"); //$NON-NLS-1$ + break; + + case 35: + style = style.setForground("MAGENTA"); //$NON-NLS-1$ + break; + + case 36: + style = style.setForground("CYAN"); //$NON-NLS-1$ + break; + + case 37: + style = style.setForground("WHITE_FOREGROUND"); //$NON-NLS-1$ + break; + + case 39: //Foreground: Default + style = style.setForground(text.getDefaultStyle().getForground()); + break; + + case 40: + style = style.setBackground("BLACK"); //$NON-NLS-1$ + break; + + case 41: + style = style.setBackground("RED"); //$NON-NLS-1$ + break; + + case 42: + style = style.setBackground("GREEN"); //$NON-NLS-1$ + break; + + case 43: + style = style.setBackground("YELLOW"); //$NON-NLS-1$ + break; + + case 44: + style = style.setBackground("BLUE"); //$NON-NLS-1$ + break; + + case 45: + style = style.setBackground("MAGENTA"); //$NON-NLS-1$ + break; + + case 46: + style = style.setBackground("CYAN"); //$NON-NLS-1$ + break; + + case 47: + style = style.setBackground("WHITE"); //$NON-NLS-1$ + break; + + case 49: //Background: Default + style = style.setBackground(text.getDefaultStyle().getBackground()); + break; + + default: + Logger + .log("Unsupported graphics rendition parameter: " + ansiParameter); //$NON-NLS-1$ + break; + } + + ++parameterIndex; + } + text.setStyle(style); + } + + /** + * This method responds to an ANSI Device Status Report (DSR) command from + * the remote endpoint requesting the ready status or the cursor position. + * Requests for other kinds of status are ignored. + */ + private void processAnsiCommand_n() { + String reply; + + if (getAnsiParameter(0) == 5) { + // Report that the terminal is ready and has no malfunctions. + reply = "\u001b[0n"; //$NON-NLS-1$ + + } else if (getAnsiParameter(0) == 6) { + // Send the ANSI cursor position (which is 1-based) to the remote + // endpoint. + reply = "\u001b[" + (relativeCursorLine() + 1) + ";" + //$NON-NLS-1$ //$NON-NLS-2$ + (getCursorColumn() + 1) + "R"; //$NON-NLS-1$ + + } else { + // Do nothing if the numeric parameter was not 5 or 6. + return; + } + + try { + terminal.getOutputStream().write(reply.getBytes("ISO-8859-1")); //$NON-NLS-1$ + terminal.getOutputStream().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. + */ + private void processAnsiCommand_P() { + text.deleteCharacters(getAnsiParameter(0)); + } + + /** + * Set Scrolling Region [top;bottom] (default = full size of window) (DECSTBM). + */ + private void processAnsiCommand_r() { + int top = 0; + int bottom = 0; + if (ansiParameters[0].length() > 0 && ansiParameters[1].length() > 0) { + top = getAnsiParameter(0); + bottom = getAnsiParameter(1); + } + text.setScrollRegion(top-1, bottom-1); + } + + /** + * Scroll up n lines (default = 1 line). + */ + private void processAnsiCommand_S() { + text.scrollUp(getAnsiParameter(0)); + } + + /** + * Scroll down n lines (default = 1 line). + */ + private void processAnsiCommand_T() { + text.scrollDown(getAnsiParameter(0)); + } + + private void processDecPrivateCommand_h() { + int param = getAnsiParameter(0); + switch (param) { + case 1: + // Enable Application Cursor Keys (DECCKM) + terminal.enableApplicationCursorKeys(true); + break; + case 47: + case 1047: + case 1048: + case 1049: + // Use Alternate Screen Buffer (ignored). + break; + default: + Logger.log("Unsupported command parameter: CSI ?" + param + 'h'); //$NON-NLS-1$ + break; + } + } + + private void processDecPrivateCommand_l() { + int param = getAnsiParameter(0); + switch (param) { + case 1: + // Enable Normal Cursor Keys (DECCKM) + terminal.enableApplicationCursorKeys(false); + break; + case 47: + case 1047: + case 1048: + case 1049: + // Use Normal Screen Buffer (ignored, but reset scroll region). + text.setScrollRegion(-1, -1); + break; + default: + Logger.log("Unsupported command parameter: CSI ?" + param + 'l'); //$NON-NLS-1$ + break; + } + } + + /** + * 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. + */ + private 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. Parameters 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 parameter characters are "20;10"). + * Parameters are integers separated by one or more ';'s. + */ + private 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. + * @throws IOException + */ + private void processNonControlCharacters(char character) throws IOException { + StringBuffer buffer=new StringBuffer(); + buffer.append(character); + // Identify a contiguous sequence of non-control characters, starting at + // firstNonControlCharacterIndex in newText. + while(hasNextChar()) { + character=getNextChar(); + if(character == '\u0000' || character == '\b' || character == '\t' + || character == '\u0007' || character == '\n' + || character == '\r' || character == '\u001b') { + pushBackChar(character); + break; + } + buffer.append(character); + } + + // Now insert the sequence of non-control characters in the StyledText widget + // at the location of the cursor. + + displayNewText(buffer.toString()); + } + + /** + * 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). + *

            + */ + private void displayNewText(String buffer) { + text.appendString(buffer); + } + + + /** + * Process a BEL (Control-G) character. + */ + private void processBEL() { + // TODO + //Display.getDefault().beep(); + } + + /** + * Process a backspace (Control-H) character. + */ + private 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. + */ + private void processTab() { + moveCursorForward(8 - (getCursorColumn() % 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". + *

            + */ + private void processNewline() { + text.processNewline(); + } + + /** + * Process a Carriage Return (Control-M). + */ + private void processCarriageReturn() { + text.setCursorColumn(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. + *

            + */ + private 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. + + // TODO +// if(text.getColumns()!=80 && text.getLines()!=80) +// text.setDimensions(24, 80); + // 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 = getConnector(); + // TODO MSA: send only if dimensions have really changed! + if (telnetConnection != null) { + telnetConnection.setTerminalSize(text.getColumns(), text.getLines()); + } + + } + + private ITerminalConnector getConnector() { + if(terminal.getTerminalConnector()!=null) + return terminal.getTerminalConnector(); + return null; + } + + /** + * This method returns the relative line number of the line containing the + * cursor. The returned line number is relative to the topmost visible line, + * which has relative line number 0. + * + * @return The relative line number of the line containing the cursor. + */ + private int relativeCursorLine() { + return text.getCursorLine(); + } + + /** + * 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. + */ + private void moveCursor(int targetLine, int targetColumn) { + text.setCursor(targetLine,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. + */ + private void moveCursorDown(int lines) { + moveCursor(relativeCursorLine() + lines, getCursorColumn()); + } + + /** + * 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. + */ + private void moveCursorUp(int lines) { + moveCursor(relativeCursorLine() - lines, getCursorColumn()); + } + + /** + * 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. + */ + private void moveCursorForward(int columnsToMove) { + moveCursor(relativeCursorLine(), getCursorColumn() + 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. + */ + private void moveCursorBackward(int columnsToMove) { + moveCursor(relativeCursorLine(), getCursorColumn() - columnsToMove); + } + /** + * Resets the state of the terminal text (foreground color, background color, + * font style and other internal state). It essentially makes it ready for new input. + */ + public void resetState() { + ansiState=ANSISTATE_INITIAL; + text.setStyle(text.getDefaultStyle()); + text.setScrollRegion(-1, -1); + text.setInsertMode(false); + } + +// public OutputStream getOutputStream() { +// return fTerminalInputStream.getOutputStream(); +// } + + /** + * Buffer for {@link #pushBackChar(char)}. + */ + private int fNextChar=-1; + + private char getNextChar() throws IOException { + int c=-1; + if(fNextChar!=-1) { + c= fNextChar; + fNextChar=-1; + } else { + c = fReader.read(); + } + // TODO: better end of file handling + if(c==-1) + c=0; + return (char)c; + } + + private boolean hasNextChar() throws IOException { + if(fNextChar>=0) + return true; + return fReader.ready(); + } + + /** + * Put back one character to the stream. This method can push + * back exactly one character. The character is the next character + * returned by {@link #getNextChar} + * @param c the character to be pushed back. + */ + void pushBackChar(char c) { + //assert fNextChar!=-1: "Already a character waiting:"+fNextChar; //$NON-NLS-1$ + fNextChar=c; + } + private int getCursorColumn() { + return text.getCursorColumn(); + } + public boolean isCrAfterNewLine() { + return fCrAfterNewLine; + } + public void setCrAfterNewLine(boolean crAfterNewLine) { + fCrAfterNewLine = crAfterNewLine; + } + void setVT100LineWrapping(boolean enable) { + text.setVT100LineWrapping(enable); + } + boolean isVT100LineWrapping() { + return text.isVT100LineWrapping(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java new file mode 100644 index 00000000000..0332edacc01 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackend.java @@ -0,0 +1,502 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [206329] Changing terminal size right after connect does not scroll properly + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.Style; + +/** + * @noextend This class is not intended to be subclassed by clients. + * @noreference This class not intended to be referenced by clients. + * It used to be package protected, and it is public only for Unit Tests. + * + */ +public class VT100EmulatorBackend implements IVT100EmulatorBackend { + + private static class ScrollRegion { + static final ScrollRegion FULL_WINDOW = new ScrollRegion(0, Integer.MAX_VALUE-1); + private final int fTop; + private final int fBottom; + ScrollRegion(int top, int bottom) { + fTop = top; + fBottom = bottom; + } + boolean contains(int line) { + return line >= fTop && line <= fBottom; + } + int getTopLine() { + return fTop; + } + int getBottomLine() { + return fBottom; + } + int getHeight() { + return fBottom - fTop + 1; + } + } + + /** + * 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 fCursorColumn is N, the next character output to the terminal appears + * in column N. When a character is output to the rightmost column on a + * given line (column widthInColumns - 1), the cursor moves to column 0 on + * the next line after the character is drawn (this is the default line wrapping + * mode). If VT100 line wrapping mode is enabled, the cursor does not move + * to the next line until the next character is printed (this is known as + * the VT100 'eat_newline_glitch'). + * 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. + *

            + */ + private int fCursorColumn; + private int fCursorLine; + /* true if last output occurred on rightmost column + * and next output requires line wrap */ + private boolean fWrapPending; + private boolean fInsertMode; + private Style fDefaultStyle; + private Style fStyle; + int fLines; + int fColumns; + final private ITerminalTextData fTerminal; + private boolean fVT100LineWrapping; + private ScrollRegion fScrollRegion = ScrollRegion.FULL_WINDOW; + + public VT100EmulatorBackend(ITerminalTextData terminal) { + fTerminal=terminal; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#clearAll() + */ + public void clearAll() { + synchronized (fTerminal) { + // clear the history + int n=fTerminal.getHeight(); + for (int line = 0; line < n; line++) { + fTerminal.cleanLine(line); + } + fTerminal.setDimensions(fLines, fTerminal.getWidth()); + setStyle(getDefaultStyle()); + setCursor(0, 0); + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setDimensions(int, int) + */ + public void setDimensions(int lines, int cols) { + synchronized (fTerminal) { + if(lines==fLines && cols==fColumns) + return; // nothing to do + // relative cursor line + int cl=getCursorLine(); + int cc=getCursorColumn(); + int height=fTerminal.getHeight(); + // absolute cursor line + int acl=cl+height-fLines; + int newLines=Math.max(lines,height); + if(lines=fCursorColumn+n; col--) { + char c=fTerminal.getChar(line, col-n); + Style style=fTerminal.getStyle(line, col-n); + fTerminal.setChar(line, col,c, style); + } + int last=Math.min(fCursorColumn+n, fColumns); + for (int col = fCursorColumn; col 0; + int line=toAbsoluteLine(fCursorLine); + int nLines=Math.min(fTerminal.getHeight()-line, fScrollRegion.getBottomLine()-fCursorLine+1); + fTerminal.scroll(line, nLines, n); + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#deleteCharacters(int) + */ + public void deleteCharacters(int n) { + synchronized (fTerminal) { + int line=toAbsoluteLine(fCursorLine); + for (int col = fCursorColumn+n; col < fColumns; col++) { + char c=fTerminal.getChar(line, col); + Style style=fTerminal.getStyle(line, col); + fTerminal.setChar(line, col-n,c, style); + } + int first=Math.max(fCursorColumn, fColumns-n); + for (int col = first; col 0; + int line=toAbsoluteLine(fCursorLine); + int nLines=Math.min(fTerminal.getHeight()-line, fScrollRegion.getBottomLine()-fCursorLine+1); + fTerminal.scroll(line, nLines, -n); + } + } + private boolean isCusorInScrollingRegion() { + return fScrollRegion.contains(fCursorLine); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getDefaultStyle() + */ + public Style getDefaultStyle() { + synchronized (fTerminal) { + return fDefaultStyle; + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setDefaultStyle(org.eclipse.tm.terminal.model.Style) + */ + public void setDefaultStyle(Style defaultStyle) { + synchronized (fTerminal) { + fDefaultStyle = defaultStyle; + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getStyle() + */ + public Style getStyle() { + synchronized (fTerminal) { + if(fStyle==null) + return fDefaultStyle; + return fStyle; + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setStyle(org.eclipse.tm.terminal.model.Style) + */ + public void setStyle(Style style) { + synchronized (fTerminal) { + fStyle=style; + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#appendString(java.lang.String) + */ + public void appendString(String buffer) { + synchronized (fTerminal) { + char[] chars=buffer.toCharArray(); + if (fInsertMode) + insertCharacters(chars.length); + int line=toAbsoluteLine(fCursorLine); + int i=0; + while (i < chars.length) { + if(fWrapPending) { + line = doLineWrap(); + } + int n=Math.min(fColumns-fCursorColumn,chars.length-i); + fTerminal.setChars(line, fCursorColumn, chars, i, n, fStyle); + int col=fCursorColumn+n; + i+=n; + // wrap needed? + if(col == fColumns) { + if (fVT100LineWrapping) { + // deferred line wrapping (eat_newline_glitch) + setCursorColumn(col - 1); + fWrapPending = true; + } else { + line = doLineWrap(); + } + } else { + setCursorColumn(col); + } + } + } + } + + private int doLineWrap() { + int line; + line=toAbsoluteLine(fCursorLine); + fTerminal.setWrappedLine(line); + doNewline(); + line=toAbsoluteLine(fCursorLine); + setCursorColumn(0); + return line; + } + + /** + * MUST be called from a synchronized block! + */ + private void doNewline() { + if (fCursorLine == fScrollRegion.getBottomLine()) + scrollUp(1); + else if (fCursorLine+1>=fLines) { + int h=fTerminal.getHeight(); + fTerminal.addLine(); + if(h!=fTerminal.getHeight()) + setCursorLine(fCursorLine+1); + } else { + setCursorLine(fCursorLine+1); + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#processNewline() + */ + public void processNewline() { + synchronized (fTerminal) { + doNewline(); + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getCursorLine() + */ + public int getCursorLine() { + synchronized (fTerminal) { + return fCursorLine; + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getCursorColumn() + */ + public int getCursorColumn() { + synchronized (fTerminal) { + return fCursorColumn; + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursor(int, int) + */ + public void setCursor(int targetLine, int targetColumn) { + synchronized (fTerminal) { + setCursorLine(targetLine); + setCursorColumn(targetColumn); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursorColumn(int) + */ + public void setCursorColumn(int targetColumn) { + synchronized (fTerminal) { + if(targetColumn<0) + targetColumn=0; + else if(targetColumn>=fColumns) + targetColumn=fColumns-1; + fCursorColumn=targetColumn; + fWrapPending = false; + // We make the assumption that nobody is changing the + // terminal cursor except this class! + // This assumption gives a huge performance improvement + fTerminal.setCursorColumn(targetColumn); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#setCursorLine(int) + */ + public void setCursorLine(int targetLine) { + synchronized (fTerminal) { + if(targetLine<0) + targetLine=0; + else if(targetLine>=fLines) + targetLine=fLines-1; + fCursorLine=targetLine; + // We make the assumption that nobody is changing the + // terminal cursor except this class! + // This assumption gives a huge performance improvement + fTerminal.setCursorLine(toAbsoluteLine(targetLine)); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getLines() + */ + public int getLines() { + synchronized (fTerminal) { + return fLines; + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.emulator.IVT100EmulatorBackend#getColumns() + */ + public int getColumns() { + synchronized (fTerminal) { + return fColumns; + } + } + + public void setVT100LineWrapping(boolean enable) { + fVT100LineWrapping = enable; + } + + public boolean isVT100LineWrapping() { + return fVT100LineWrapping; + } + + public void setInsertMode(boolean enable) { + fInsertMode = enable; + } + + public void setScrollRegion(int top, int bottom) { + if (top < 0 || bottom < 0) + fScrollRegion = ScrollRegion.FULL_WINDOW; + else if (top < bottom) + fScrollRegion = new ScrollRegion(top, bottom); + } + + public void scrollUp(int n) { + assert n>0; + synchronized (fTerminal) { + int line = toAbsoluteLine(fScrollRegion.getTopLine()); + int nLines = Math.min(fTerminal.getHeight()-line, fScrollRegion.getHeight()); + fTerminal.scroll(line, nLines, -n); + } + } + + public void scrollDown(int n) { + assert n>0; + synchronized (fTerminal) { + int line = toAbsoluteLine(fScrollRegion.getTopLine()); + int nLines = Math.min(fTerminal.getHeight()-line, fScrollRegion.getHeight()); + fTerminal.scroll(line, nLines, n); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java new file mode 100644 index 00000000000..9f07dc37036 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/emulator/VT100TerminalControl.java @@ -0,0 +1,1419 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [206892] State handling: Only allow connect when CLOSED + * Martin Oberhuber (Wind River) - [206883] Serial Terminal leaks Jobs + * Martin Oberhuber (Wind River) - [208145] Terminal prints garbage after quick disconnect/reconnect + * Martin Oberhuber (Wind River) - [207785] NPE when trying to send char while no longer connected + * Michael Scharf (Wind River) - [209665] Add ability to log byte streams from terminal + * Ruslan Sychev (Xored Software) - [217675] NPE or SWTException when closing Terminal View while connection establishing + * Michael Scharf (Wing River) - [196447] The optional terminal input line should be resizeable + * Martin Oberhuber (Wind River) - [168197] Replace JFace MessagDialog by SWT MessageBox + * Martin Oberhuber (Wind River) - [204796] Terminal should allow setting the encoding to use + * Michael Scharf (Wind River) - [237398] Terminal get Invalid Thread Access when the title is set + * Martin Oberhuber (Wind River) - [240745] Pressing Ctrl+F1 in the Terminal should bring up context help + * Michael Scharf (Wind River) - [240098] The cursor should not blink when the terminal is disconnected + * Anton Leherbauer (Wind River) - [335021] Middle mouse button copy/paste does not work with the terminal + * Max Stepanov (Appcelerator) - [339768] Fix ANSI code for PgUp / PgDn + * Pawel Piech (Wind River) - [333613] "Job found still running" after shutdown + * Martin Oberhuber (Wind River) - [348700] Terminal unusable after disconnect + * Simon Bernard (Sierra Wireless) - [351424] [terminal] Terminal does not support del and insert key + * Martin Oberhuber (Wind River) - [265352][api] Allow setting fonts programmatically + * Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + * Anton Leherbauer (Wind River) - [434294] Incorrect handling of function keys with modifiers + * Martin Oberhuber (Wind River) - [434294] Add Mac bindings with COMMAND + * Anton Leherbauer (Wind River) - [434749] UnhandledEventLoopException when copying to clipboard while the selection is empty + * Martin Oberhuber (Wind River) - [436612] Restore Eclipse 3.4 compatibility by using Reflection + * Anton Leherbauer (Wind River) - [458398] Add support for normal/application cursor keys mode + * Anton Leherbauer (Wind River) - [420928] Terminal widget leaks memory + * Davy Landman (CWI) - [475267][api] Allow custom mouse listeners + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.lang.reflect.Field; +import java.net.SocketException; +import java.nio.charset.Charset; + +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.core.runtime.jobs.Job; +import org.eclipse.jface.bindings.Binding; +import org.eclipse.jface.bindings.keys.KeySequence; +import org.eclipse.jface.bindings.keys.KeyStroke; +import org.eclipse.jface.bindings.keys.SWTKeySupport; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.KeyAdapter; +import org.eclipse.swt.events.KeyEvent; +import org.eclipse.swt.events.KeyListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseTrackListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.internal.terminal.control.ICommandInputField; +import org.eclipse.tm.internal.terminal.control.ITerminalListener; +import org.eclipse.tm.internal.terminal.control.ITerminalListener2; +import org.eclipse.tm.internal.terminal.control.ITerminalMouseListener; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.impl.ITerminalControlForText; +import org.eclipse.tm.internal.terminal.control.impl.TerminalMessages; +import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin; +import org.eclipse.tm.internal.terminal.preferences.ITerminalConstants; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.textcanvas.PipedInputStream; +import org.eclipse.tm.internal.terminal.textcanvas.PollingTextCanvasModel; +import org.eclipse.tm.internal.terminal.textcanvas.TextCanvas; +import org.eclipse.tm.internal.terminal.textcanvas.TextLineRenderer; +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; +import org.eclipse.tm.terminal.model.TerminalTextDataFactory; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.keys.IBindingService; + +/** + * + * This class was originally written to use nested classes, which unfortunately makes + * this source file larger and more complex than it needs to be. In particular, the + * methods in the nested classes directly access the fields of the enclosing class. + * One day we should pull the nested classes out into their own source files (but still + * in this package). + * + * @author Chris Thew + */ +public class VT100TerminalControl implements ITerminalControlForText, ITerminalControl, ITerminalViewControl +{ + protected final static String[] LINE_DELIMITERS = { "\n" }; //$NON-NLS-1$ + + /** + * This field holds a reference to a TerminalText object that performs all ANSI + * text processing on data received from the remote host and controls how text is + * displayed using the view's StyledText widget. + */ + private final VT100Emulator fTerminalText; + private Display fDisplay; + private TextCanvas fCtlText; + private Composite fWndParent; + private Clipboard fClipboard; + private KeyListener fKeyHandler; + private final ITerminalListener fTerminalListener; + private String fMsg = ""; //$NON-NLS-1$ + private TerminalMouseTrackListener fFocusListener; + private ITerminalConnector fConnector; + private final ITerminalConnector[] fConnectors; + private final boolean fUseCommonPrefs; + private boolean connectOnEnterIfClosed = true; + + PipedInputStream fInputStream; + private static final String defaultEncoding = Charset.defaultCharset().name(); + private String fEncoding = defaultEncoding; + private InputStreamReader fInputStreamReader; + + private ICommandInputField fCommandInputField; + + private volatile TerminalState fState; + + private final ITerminalTextData fTerminalModel; + + private final EditActionAccelerators editActionAccelerators = new EditActionAccelerators(); + + private boolean fApplicationCursorKeys; + + /** + * Listens to changes in the preferences + */ + private final IPropertyChangeListener fPreferenceListener=new IPropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + if(event.getProperty().equals(ITerminalConstants.PREF_BUFFERLINES) + || event.getProperty().equals(ITerminalConstants.PREF_INVERT_COLORS)) { + updatePreferences(); + } + } + }; + private final IPropertyChangeListener fFontListener = new IPropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + if (event.getProperty().equals(ITerminalConstants.FONT_DEFINITION)) { + onTerminalFontChanged(); + } + } + }; + + /** + * Is protected by synchronize on this + */ + volatile private Job fJob; + + private PollingTextCanvasModel fPollingTextCanvasModel; + + public VT100TerminalControl(ITerminalListener target, Composite wndParent, ITerminalConnector[] connectors) { + this(target, wndParent, connectors, false); + } + + /** + * Instantiate a Terminal widget. + * @param target Callback for notifying the owner of Terminal state changes. + * @param wndParent The Window parent to embed the Terminal in. + * @param connectors Provided connectors. + * @param useCommonPrefs If true, the Terminal widget will pick up settings + * from the org.eclipse.tm.terminal.TerminalPreferencePage Preference page. + * Otherwise, clients need to maintain settings themselves. + * @since 3.2 + */ + public VT100TerminalControl(ITerminalListener target, Composite wndParent, ITerminalConnector[] connectors, boolean useCommonPrefs) { + fConnectors=connectors; + fUseCommonPrefs = useCommonPrefs; + fTerminalListener=target; + fTerminalModel=TerminalTextDataFactory.makeTerminalTextData(); + fTerminalModel.setMaxHeight(1000); + fInputStream=new PipedInputStream(8*1024); + fTerminalText = new VT100Emulator(fTerminalModel, this, null); + try { + // Use Default Encoding as start, until setEncoding() is called + setEncoding(null); + } catch (UnsupportedEncodingException e) { + // Should never happen + e.printStackTrace(); + // Fall back to local Platform Default Encoding + fEncoding = defaultEncoding; + fInputStreamReader = new InputStreamReader(fInputStream); + fTerminalText.setInputStreamReader(fInputStreamReader); + } + + setupTerminal(wndParent); + } + + @Override + public void setEncoding(String encoding) throws UnsupportedEncodingException { + if (encoding == null) { + // TODO better use a standard remote-to-local encoding? + encoding = "ISO-8859-1"; //$NON-NLS-1$ + // TODO or better use the local default encoding? + // encoding = defaultEncoding; + } + fInputStreamReader = new InputStreamReader(fInputStream, encoding); + // remember encoding if above didn't throw an exception + fEncoding = encoding; + fTerminalText.setInputStreamReader(fInputStreamReader); + } + + @Override + public String getEncoding() { + return fEncoding; + } + + @Override + public ITerminalConnector[] getConnectors() { + return fConnectors; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#copy() + */ + @Override + public void copy() { + copy(DND.CLIPBOARD); + } + + private void copy(int clipboardType) { + String selection = getSelection(); + if (selection.length() > 0) { + Object[] data = new Object[] { selection }; + Transfer[] types = new Transfer[] { TextTransfer.getInstance() }; + fClipboard.setContents(data, types, clipboardType); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#paste() + */ + @Override + public void paste() { + paste(DND.CLIPBOARD); +// 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(); + } + + private void paste(int clipboardType) { + TextTransfer textTransfer = TextTransfer.getInstance(); + String strText = (String) fClipboard.getContents(textTransfer, clipboardType); + pasteString(strText); + } + + /** + * @param strText the text to paste + */ + @Override + public boolean pasteString(String strText) { + if(!isConnected()) + return false; + if (strText == null) + return false; + if (!fEncoding.equals(defaultEncoding)) { + sendString(strText); + } else { + // TODO I do not understand why pasteString would do this here... + for (int i = 0; i < strText.length(); i++) { + sendChar(strText.charAt(i), false); + } + } + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#selectAll() + */ + @Override + public void selectAll() { + getCtlText().selectAll(); + if (fTerminalListener instanceof ITerminalListener2) { + ((ITerminalListener2)fTerminalListener).setTerminalSelectionChanged(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#sendKey(char) + */ + @Override + public void sendKey(char character) { + Event event; + KeyEvent keyEvent; + + event = new Event(); + event.widget = getCtlText(); + event.character = character; + event.keyCode = 0; + event.stateMask = 0; + event.doit = true; + keyEvent = new KeyEvent(event); + + fKeyHandler.keyPressed(keyEvent); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#clearTerminal() + */ + @Override + public void clearTerminal() { + // The TerminalText object does all text manipulation. + getTerminalText().clearTerminal(); + getCtlText().clearSelection(); + if (fTerminalListener instanceof ITerminalListener2) { + ((ITerminalListener2)fTerminalListener).setTerminalSelectionChanged(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getClipboard() + */ + @Override + public Clipboard getClipboard() { + return fClipboard; + } + + /** + * @return non null selection + */ + @Override + public String getSelection() { + String txt= fCtlText.getSelectionText(); + if(txt==null) + txt=""; //$NON-NLS-1$ + return txt; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setFocus() + */ + @Override + public void setFocus() { + getCtlText().setFocus(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isEmpty() + */ + @Override + public boolean isEmpty() { + return getCtlText().isEmpty(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isDisposed() + */ + @Override + public boolean isDisposed() { + return getCtlText().isDisposed(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isConnected() + */ + @Override + public boolean isConnected() { + return fState==TerminalState.CONNECTED; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#disposeTerminal() + */ + @Override + public void disposeTerminal() { + Logger.log("entered."); //$NON-NLS-1$ + if(fUseCommonPrefs) { + TerminalPlugin.getDefault().getPreferenceStore().removePropertyChangeListener(fPreferenceListener); + JFaceResources.getFontRegistry().removeListener(fFontListener); + } + disconnectTerminal(); + fClipboard.dispose(); + getTerminalText().dispose(); + } + + @Override + public void connectTerminal() { + Logger.log("entered."); //$NON-NLS-1$ + if(getTerminalConnector()==null) + return; + fTerminalText.resetState(); + fApplicationCursorKeys = false; + if(fConnector.getInitializationErrorMessage()!=null) { + showErrorMessage(NLS.bind( + TerminalMessages.CannotConnectTo, + fConnector.getName(), + fConnector.getInitializationErrorMessage())); + // we cannot connect because the connector was not initialized + return; + } + // clean the error message + setMsg(""); //$NON-NLS-1$ + getTerminalConnector().connect(this); + waitForConnect(); + } + + @Override + public ITerminalConnector getTerminalConnector() { + return fConnector; + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#disconnectTerminal() + */ + @Override + public void disconnectTerminal() { + Logger.log("entered."); //$NON-NLS-1$ + + //Disconnect the remote side first + if (getState()!=TerminalState.CLOSED) { + if(getTerminalConnector()!=null) { + getTerminalConnector().disconnect(); + } + } + + //Ensure that a new Job can be started; then clean up old Job. + Job job; + synchronized(this) { + job = fJob; + fJob = null; + } + if (job!=null) { + job.cancel(); + // Join job to avoid leaving job running after workbench shutdown (333613). + // Interrupt to be fast enough; cannot close fInputStream since it is re-used (bug 348700). + Thread t = job.getThread(); + if(t!=null) t.interrupt(); + try { + job.join(); + } catch (InterruptedException e) {} + } + fPollingTextCanvasModel.stopPolling(); + } + + private void waitForConnect() { + Logger.log("entered."); //$NON-NLS-1$ + + // TODO Eliminate the nested dispatch loop + do { + if (!fDisplay.readAndDispatch()) + fDisplay.sleep(); + } while (getState()==TerminalState.CONNECTING); + + if (getCtlText().isDisposed()) { + disconnectTerminal(); + return; + } + if (getMsg().length() > 0) { + showErrorMessage(getMsg()); + disconnectTerminal(); + return; + } + if (getCtlText().isFocusControl()) { + if (getState() == TerminalState.CONNECTED) + fFocusListener.captureKeyEvents(true); + } + fPollingTextCanvasModel.startPolling(); + startReaderJob(); + } + + private synchronized void startReaderJob() { + if(fJob==null) { + fJob=new Job("Terminal data reader") { //$NON-NLS-1$ + @Override + protected IStatus run(IProgressMonitor monitor) { + IStatus status=Status.OK_STATUS; + try { + while(true) { + while(fInputStream.available()==0 && !monitor.isCanceled()) { + try { + fInputStream.waitForAvailable(500); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + if(monitor.isCanceled()) { + //Do not disconnect terminal here because another reader job may already be running + status=Status.CANCEL_STATUS; + break; + } + try { + // TODO: should block when no text is available! + fTerminalText.processText(); + } catch (Exception e) { + disconnectTerminal(); + status=new Status(IStatus.ERROR,TerminalPlugin.PLUGIN_ID,e.getLocalizedMessage(),e); + break; + } + } + } finally { + // clean the job: start a new one when the connection gets restarted + // Bug 208145: make sure we do not clean an other job that's already started (since it would become a Zombie) + synchronized (VT100TerminalControl.this) { + if (fJob==this) { + fJob=null; + } + } + } + return status; + } + + }; + fJob.setSystem(true); + fJob.schedule(); + } + } + + private void showErrorMessage(String message) { + String strTitle = TerminalMessages.TerminalError; + // [168197] Replace JFace MessagDialog by SWT MessageBox + //MessageDialog.openError( getShell(), strTitle, message); + MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK); + mb.setText(strTitle); + mb.setMessage(message); + mb.open(); + } + + protected void sendString(String string) { + Logger.log(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. + // TODO: handle Encoding Errors in a better way + + getOutputStream().write(string.getBytes(fEncoding)); + getOutputStream().flush(); + } catch (SocketException socketException) { + displayTextInTerminal(socketException.getMessage()); + + String strMsg = TerminalMessages.SocketError + + "!\n" + socketException.getMessage(); //$NON-NLS-1$ + showErrorMessage(strMsg); + + Logger.logException(socketException); + + disconnectTerminal(); + } catch (IOException ioException) { + showErrorMessage(TerminalMessages.IOError + "!\n" + ioException.getMessage());//$NON-NLS-1$ + + Logger.logException(ioException); + + disconnectTerminal(); + } + } + + @Override + public Shell getShell() { + return getCtlText().getShell(); + } + + protected void sendChar(char chKey, boolean altKeyPressed) { + try { + int byteToSend = chKey; + OutputStream os = getOutputStream(); + if (os==null) { + // Bug 207785: NPE when trying to send char while no longer connected + Logger.log("NOT sending '" + byteToSend + "' because no longer connected"); //$NON-NLS-1$ //$NON-NLS-2$ + } else { + 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. + + byte[] bytesToSend = String.valueOf(chKey).getBytes(fEncoding); + StringBuilder b = new StringBuilder("sending ESC"); //$NON-NLS-1$ + for (int i = 0; i < bytesToSend.length; i++) { + if (i != 0) b.append(" +"); //$NON-NLS-1$ + b.append(" '" + bytesToSend[i] + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + } + Logger.log(b.toString()); + os.write('\u001b'); + os.write(bytesToSend); + } else { + byte[] bytesToSend = String.valueOf(chKey).getBytes(fEncoding); + StringBuilder b = new StringBuilder("sending"); //$NON-NLS-1$ + for (int i = 0; i < bytesToSend.length; i++) { + if (i != 0) b.append(" +"); //$NON-NLS-1$ + b.append(" '" + bytesToSend[i] + "'"); //$NON-NLS-1$ //$NON-NLS-2$ + } + Logger.log(b.toString()); + os.write(bytesToSend); + } + os.flush(); + } + } catch (SocketException socketException) { + Logger.logException(socketException); + + displayTextInTerminal(socketException.getMessage()); + + String strMsg = TerminalMessages.SocketError + + "!\n" + socketException.getMessage(); //$NON-NLS-1$ + + showErrorMessage(strMsg); + Logger.logException(socketException); + + disconnectTerminal(); + } catch (IOException ioException) { + Logger.logException(ioException); + + displayTextInTerminal(ioException.getMessage()); + + String strMsg = TerminalMessages.IOError + "!\n" + ioException.getMessage(); //$NON-NLS-1$ + + showErrorMessage(strMsg); + Logger.logException(ioException); + + disconnectTerminal(); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setupTerminal(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupTerminal(Composite parent) { + Assert.isNotNull(parent); + boolean wasDisposed = true; + TerminalState oldState = fState; + fState = TerminalState.CLOSED; + if (fClipboard != null && !fClipboard.isDisposed()) { + // terminal was not disposed (DnD) + wasDisposed = false; + fClipboard.dispose(); + fPollingTextCanvasModel.stopPolling(); + } + if (fWndParent != null && !fWndParent.isDisposed()) { + // terminal widget gets a new parent (DnD) + fWndParent.dispose(); + } + setupControls(parent); + setCommandInputField(fCommandInputField); + setupListeners(); + if (fUseCommonPrefs && wasDisposed) { + updatePreferences(); + onTerminalFontChanged(); + TerminalPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(fPreferenceListener); + JFaceResources.getFontRegistry().addListener(fFontListener); + } + setupHelp(fWndParent, TerminalPlugin.HELP_VIEW); + + if (!wasDisposed) { + fState = oldState; + } + } + + /* + * (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalViewControl#updatePreferences() + */ + private void updatePreferences() { + int bufferLineLimit = Platform.getPreferencesService().getInt(TerminalPlugin.PLUGIN_ID, ITerminalConstants.PREF_BUFFERLINES, 0, null); + boolean invert = Platform.getPreferencesService().getBoolean(TerminalPlugin.PLUGIN_ID, ITerminalConstants.PREF_INVERT_COLORS, false, null); + setBufferLineLimit(bufferLineLimit); + setInvertedColors(invert); + } + + private void onTerminalFontChanged() { + // set the font for all + setFont(ITerminalConstants.FONT_DEFINITION); + } + + /* + * (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalViewControl#setFont(java.lang.String) + */ + @Override + public void setFont(String fontName) { + Font font=JFaceResources.getFont(fontName); + getCtlText().setFont(font); + if(fCommandInputField!=null) { + fCommandInputField.setFont(font); + } + // Tell the TerminalControl singleton that the font has changed. + fCtlText.updateFont(fontName); + getTerminalText().fontChanged(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalViewControl#setFont(org.eclipse.swt.graphics.Font) + */ + @Override + @Deprecated + public void setFont(Font font) { + getCtlText().setFont(font); + if(fCommandInputField!=null) { + fCommandInputField.setFont(font); + } + + // Tell the TerminalControl singleton that the font has changed. + fCtlText.onFontChange(); + getTerminalText().fontChanged(); + } + @Override + public Font getFont() { + return getCtlText().getFont(); + } + @Override + public Control getControl() { + return fCtlText; + } + @Override + public Control getRootControl() { + return fWndParent; + } + protected void setupControls(Composite parent) { + fWndParent=new Composite(parent,SWT.NONE); + GridLayout layout=new GridLayout(); + layout.marginWidth=0; layout.marginHeight=0; layout.verticalSpacing=0; + fWndParent.setLayout(layout); + + ITerminalTextDataSnapshot snapshot=fTerminalModel.makeSnapshot(); + // TODO how to get the initial size correctly! + snapshot.updateSnapshot(false); + fPollingTextCanvasModel=new PollingTextCanvasModel(snapshot); + fCtlText=new TextCanvas(fWndParent,fPollingTextCanvasModel,SWT.NONE,new TextLineRenderer(fCtlText,fPollingTextCanvasModel)); + + fCtlText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + fCtlText.addResizeHandler(new TextCanvas.ResizeListener() { + @Override + public void sizeChanged(int lines, int columns) { + fTerminalText.setDimensions(lines, columns); + } + }); + fCtlText.addMouseListener(new MouseAdapter() { + @Override + public void mouseUp(MouseEvent e) { + // update selection used by middle mouse button paste + if (e.button == 1 && getSelection().length() > 0) { + copy(DND.SELECTION_CLIPBOARD); + } + } + }); + + fDisplay = getCtlText().getDisplay(); + fClipboard = new Clipboard(fDisplay); + } + + protected void setupListeners() { + fKeyHandler = new TerminalKeyHandler(); + fFocusListener = new TerminalMouseTrackListener(); + + getCtlText().addKeyListener(fKeyHandler); + getCtlText().addMouseTrackListener(fFocusListener); + + } + + /** + * Setup all the help contexts for the controls. + */ + protected void setupHelp(Composite parent, String id) { + Control[] children = parent.getChildren(); + + for (int nIndex = 0; nIndex < children.length; nIndex++) { + if (children[nIndex] instanceof Composite) { + setupHelp((Composite) children[nIndex], id); + } + } + + PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, id); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#displayTextInTerminal(java.lang.String) + */ + @Override + public void displayTextInTerminal(String text) { + writeToTerminal("\r\n"+text+"\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + private void writeToTerminal(String text) { + try { + getRemoteToTerminalOutputStream().write(text.getBytes(fEncoding)); + } catch (UnsupportedEncodingException e) { + // should never happen! + e.printStackTrace(); + } catch (IOException e) { + // should never happen! + e.printStackTrace(); + } + } + + @Override + public OutputStream getRemoteToTerminalOutputStream() { + if(Logger.isLogEnabled()) { + return new LoggingOutputStream(fInputStream.getOutputStream()); + } else { + return fInputStream.getOutputStream(); + } + } + protected boolean isLogCharEnabled() { + return TerminalPlugin.isOptionEnabled(Logger.TRACE_DEBUG_LOG_CHAR); + } + + @Override + public OutputStream getOutputStream() { + if(getTerminalConnector()!=null) + return getTerminalConnector().getTerminalToRemoteStream(); + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setMsg(java.lang.String) + */ + @Override + public void setMsg(String msg) { + fMsg = msg; + } + + public String getMsg() { + return fMsg; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getCtlText() + */ + protected TextCanvas getCtlText() { + return fCtlText; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#getTerminalText() + */ + public VT100Emulator getTerminalText() { + return fTerminalText; + } + protected class TerminalMouseTrackListener implements MouseTrackListener { + private IContextActivation terminalContextActivation = null; + private IContextActivation editContextActivation = null; + + protected TerminalMouseTrackListener() { + super(); + } + + @Override + public void mouseHover(MouseEvent e) { + } + + @Override + @SuppressWarnings("cast") + public void mouseEnter(MouseEvent e) { + // 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. + if (getState() == TerminalState.CONNECTED) + captureKeyEvents(true); + + IContextService contextService = (IContextService) PlatformUI.getWorkbench().getAdapter(IContextService.class); + editContextActivation = contextService.activateContext("org.eclipse.tm.terminal.EditContext"); //$NON-NLS-1$ + } + + @Override + @SuppressWarnings("cast") + public void mouseExit(MouseEvent e) { + // Enable all keybindings. + captureKeyEvents(false); + + // Restore the command context to its previous value. + + IContextService contextService = (IContextService) PlatformUI.getWorkbench().getAdapter(IContextService.class); + contextService.deactivateContext(editContextActivation); + } + + @SuppressWarnings("cast") + protected void captureKeyEvents(boolean capture) { + IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class); + IContextService contextService = (IContextService) PlatformUI.getWorkbench().getAdapter(IContextService.class); + + boolean enableKeyFilter = !capture; + if (bindingService.isKeyFilterEnabled() != enableKeyFilter) + bindingService.setKeyFilterEnabled(enableKeyFilter); + + if (capture && terminalContextActivation == null) { + // 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 absolutely _all_ + // key-presses. + terminalContextActivation = contextService.activateContext("org.eclipse.tm.terminal.TerminalContext"); //$NON-NLS-1$ + + } else if (!capture && terminalContextActivation != null) { + contextService.deactivateContext(terminalContextActivation); + terminalContextActivation = null; + } + } + } + + protected class TerminalKeyHandler extends KeyAdapter { + @Override + public void keyPressed(KeyEvent event) { + //TODO next 2 lines are probably obsolete now + if (getState()==TerminalState.CONNECTING) + return; + + //TODO we should no longer handle copy & paste specially. + //Instead, we should have Ctrl+Shift always go to local since there is no escape sequence for this. + //On Mac, Command+Anything already goes always to local. + //Note that this decision means that Command will NOT be Meta in Emacs on a Remote. + int accelerator = SWTKeySupport.convertEventToUnmodifiedAccelerator(event); + if (editActionAccelerators.isCopyAction(accelerator)) { + copy(); + return; + } + if (editActionAccelerators.isPasteAction(accelerator)) { + paste(); + 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; + int modifierKeys = event.stateMask & SWT.MODIFIER_MASK; + boolean ctrlKeyPressed = (event.stateMask & SWT.CTRL) != 0; + boolean onlyCtrlKeyPressed = modifierKeys == SWT.CTRL; + boolean macCmdKeyPressed = (event.stateMask & SWT.COMMAND) != 0; + + // 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. + boolean altKeyPressed = (event.stateMask & SWT.ALT) != 0 && !ctrlKeyPressed; + + //if (!isConnected()) { + if (fState==TerminalState.CLOSED) { + // Pressing ENTER while not connected causes us to connect. + if (character == '\r' && isConnectOnEnterIfClosed()) { + connectTerminal(); + return; + } + + // Ignore all other keyboard input when not connected. + // Allow other key handlers (such as Ctrl+F1) do their work + event.doit = true; + return; + } + + // Manage the Del key + if (event.keyCode == 0x000007f) { + sendString("\u001b[3~"); //$NON-NLS-1$ + return; + } + + // TODO Linux tty is usually expecting a DEL (^?) character + // but this causes issues with some telnet servers and + // serial connections. Workaround: stty erase ^H + //if (event.keyCode == SWT.BS) { + // sendChar(SWT.DEL, altKeyPressed); + // 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. + // On a Mac, the Cmd key is always used for local commands. + + if (macCmdKeyPressed || (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. + + String escSeq = null; + boolean anyModifierPressed = modifierKeys != 0; + boolean onlyMacCmdKeyPressed = modifierKeys == SWT.COMMAND; + + switch (event.keyCode) { + case 0x1000001: // Up arrow. + if (!anyModifierPressed) + escSeq = fApplicationCursorKeys ? "\u001bOA" : "\u001b[A"; //$NON-NLS-1$ //$NON-NLS-2$ + break; + + case 0x1000002: // Down arrow. + if (!anyModifierPressed) + escSeq = fApplicationCursorKeys ? "\u001bOB" : "\u001b[B"; //$NON-NLS-1$ //$NON-NLS-2$ + break; + + case 0x1000003: // Left arrow. + if (onlyCtrlKeyPressed) { + escSeq = "\u001b[1;5D"; //$NON-NLS-1$ + } else if (!anyModifierPressed) { + escSeq = fApplicationCursorKeys ? "\u001bOD" : "\u001b[D"; //$NON-NLS-1$ //$NON-NLS-2$ + } else if (onlyMacCmdKeyPressed) { + // Cmd-Left is "Home" on the Mac + escSeq = fApplicationCursorKeys ? "\u001bOH" : "\u001b[H"; //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + + case 0x1000004: // Right arrow. + if (onlyCtrlKeyPressed) { + escSeq = "\u001b[1;5C"; //$NON-NLS-1$ + } else if (!anyModifierPressed) { + escSeq = fApplicationCursorKeys ? "\u001bOC" : "\u001b[C"; //$NON-NLS-1$ //$NON-NLS-2$ + } else if (onlyMacCmdKeyPressed) { + // Cmd-Right is "End" on the Mac + escSeq = fApplicationCursorKeys ? "\u001bOF" : "\u001b[F"; //$NON-NLS-1$ //$NON-NLS-2$ + } + break; + + case 0x1000005: // PgUp key. + if (!anyModifierPressed) + escSeq = "\u001b[5~"; //$NON-NLS-1$ + break; + + case 0x1000006: // PgDn key. + if (!anyModifierPressed) + escSeq = "\u001b[6~"; //$NON-NLS-1$ + break; + + case 0x1000007: // Home key. + if (!anyModifierPressed) + escSeq = fApplicationCursorKeys ? "\u001bOH" : "\u001b[H"; //$NON-NLS-1$ //$NON-NLS-2$ + break; + + case 0x1000008: // End key. + if (!anyModifierPressed) + escSeq = fApplicationCursorKeys ? "\u001bOF" : "\u001b[F"; //$NON-NLS-1$ //$NON-NLS-2$ + break; + + case 0x1000009: // Insert. + if (!anyModifierPressed) + escSeq = "\u001b[2~"; //$NON-NLS-1$ + break; + + case 0x100000a: // F1 key. + if (!anyModifierPressed) + escSeq = "\u001bOP"; //$NON-NLS-1$ + break; + + case 0x100000b: // F2 key. + if (!anyModifierPressed) + escSeq = "\u001bOQ"; //$NON-NLS-1$ + break; + + case 0x100000c: // F3 key. + if (!anyModifierPressed) + escSeq = "\u001bOR"; //$NON-NLS-1$ + break; + + case 0x100000d: // F4 key. + if (!anyModifierPressed) + escSeq = "\u001bOS"; //$NON-NLS-1$ + break; + + case 0x100000e: // F5 key. + if (!anyModifierPressed) + escSeq = "\u001b[15~"; //$NON-NLS-1$ + break; + + case 0x100000f: // F6 key. + if (!anyModifierPressed) + escSeq = "\u001b[17~"; //$NON-NLS-1$ + break; + + case 0x1000010: // F7 key. + if (!anyModifierPressed) + escSeq = "\u001b[18~"; //$NON-NLS-1$ + break; + + case 0x1000011: // F8 key. + if (!anyModifierPressed) + escSeq = "\u001b[19~"; //$NON-NLS-1$ + break; + + case 0x1000012: // F9 key. + if (!anyModifierPressed) + escSeq = "\u001b[20~"; //$NON-NLS-1$ + break; + + case 0x1000013: // F10 key. + if (!anyModifierPressed) + escSeq = "\u001b[21~"; //$NON-NLS-1$ + break; + + case 0x1000014: // F11 key. + if (!anyModifierPressed) + escSeq = "\u001b[23~"; //$NON-NLS-1$ + break; + + case 0x1000015: // F12 key. + if (!anyModifierPressed) + escSeq = "\u001b[24~"; //$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; + } + + if (escSeq == null) { + // Any unmapped key should be handled locally by Eclipse + event.doit = true; + processKeyBinding(event, accelerator); + } else + sendString(escSeq); + + // It's ok to return here, because we never locally echo special keys. + + return; + } + + Logger.log("stateMask = " + event.stateMask); //$NON-NLS-1$ + + if (onlyCtrlKeyPressed) { + switch (character) { + case ' ': + // 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'; + break; + case '/': + // Ctrl+/ is undo in emacs + character = '\u001f'; + break; + } + } + + //TODO: At this point, Ctrl+M sends the same as Ctrl+Shift+M . + //This is undesired. Fixing this here might make the special Ctrl+Shift+C + //handling unnecessary further up. + sendChar(character, altKeyPressed); + + // 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 (getTerminalConnector() == null + || getTerminalConnector().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()); + } + + /* + * Process given event as Eclipse key binding. + */ + @SuppressWarnings("cast") + private void processKeyBinding(KeyEvent event, int accelerator) { + IBindingService bindingService = (IBindingService) PlatformUI.getWorkbench().getAdapter(IBindingService.class); + KeyStroke keyStroke = SWTKeySupport.convertAcceleratorToKeyStroke(accelerator); + Binding binding = bindingService.getPerfectMatch(KeySequence.getInstance(keyStroke)); + if (binding != null) { + ParameterizedCommand cmd = binding.getParameterizedCommand(); + if (cmd != null) { + IHandlerService handlerService = (IHandlerService) PlatformUI.getWorkbench().getAdapter(IHandlerService.class); + Event cmdEvent = new Event(); + cmdEvent.type = SWT.KeyDown; + cmdEvent.display = event.display; + cmdEvent.widget = event.widget; + cmdEvent.character = event.character; + cmdEvent.keyCode = event.keyCode; + ////Bug - KeyEvent.keyLocation was introduced in Eclipse 3.6 + ////Use reflection for now to remain backward compatible down to Eclipse 3.4 + //cmdEvent.keyLocation = event.keyLocation; + try { + Field f1 = event.getClass().getField("keyLocation"); //$NON-NLS-1$ + Field f2 = cmdEvent.getClass().getField("keyLocation"); //$NON-NLS-1$ + f2.set(cmdEvent, f1.get(event)); + } catch(NoSuchFieldException nsfe) { + /* ignore, this is Eclipse 3.5 or earlier */ + } catch(Throwable t) { + t.printStackTrace(); + } + cmdEvent.stateMask = event.stateMask; + event.doit = false; + try { + handlerService.executeCommand(cmd, cmdEvent); + } catch (ExecutionException e) { + TerminalPlugin.getDefault().getLog().log( + new Status(IStatus.ERROR,TerminalPlugin.PLUGIN_ID,e.getLocalizedMessage(),e)); + } catch (Exception e) { + // ignore other exceptions from cmd execution + } + } + } + } + + } + + @Override + public void setTerminalTitle(String title) { + fTerminalListener.setTerminalTitle(title); + } + + + @Override + public TerminalState getState() { + return fState; + } + + + @Override + public void setState(TerminalState state) { + fState=state; + fTerminalListener.setState(state); + // enable the (blinking) cursor if the terminal is connected + runAsyncInDisplayThread(new Runnable() { + @Override + public void run() { + if(fCtlText!=null && !fCtlText.isDisposed()) { + if (isConnected()) { + fCtlText.setCursorEnabled(true); + } else { + fCtlText.setCursorEnabled(false); + // Stop capturing all key events + fFocusListener.captureKeyEvents(false); + } + } + } + }); + } + /** + * @param runnable run in display thread + */ + private void runAsyncInDisplayThread(Runnable runnable) { + if(Display.findDisplay(Thread.currentThread())!=null) + runnable.run(); + else if(PlatformUI.isWorkbenchRunning() && PlatformUI.getWorkbench().getDisplay() != null && !PlatformUI.getWorkbench().getDisplay().isDisposed()) + PlatformUI.getWorkbench().getDisplay().asyncExec(runnable); + // else should not happen and we ignore it... + } + + @Override + public String getSettingsSummary() { + if(getTerminalConnector()!=null) + return getTerminalConnector().getSettingsSummary(); + return ""; //$NON-NLS-1$ + } + + @Override + public void setConnector(ITerminalConnector connector) { + fConnector=connector; + + } + @Override + public ICommandInputField getCommandInputField() { + return fCommandInputField; + } + + @Override + public void setCommandInputField(ICommandInputField inputField) { + if(fCommandInputField!=null) + fCommandInputField.dispose(); + fCommandInputField=inputField; + if(fCommandInputField!=null) + fCommandInputField.createControl(fWndParent, this); + if(fWndParent.isVisible()) + fWndParent.layout(true); + } + + @Override + public int getBufferLineLimit() { + return fTerminalModel.getMaxHeight(); + } + + @Override + public void setBufferLineLimit(int bufferLineLimit) { + if(bufferLineLimit<=0) + return; + synchronized (fTerminalModel) { + if(fTerminalModel.getHeight()>bufferLineLimit) + fTerminalModel.setDimensions(bufferLineLimit, fTerminalModel.getWidth()); + fTerminalModel.setMaxHeight(bufferLineLimit); + } + } + + @Override + public boolean isScrollLock() { + return fCtlText.isScrollLock(); + } + + @Override + public void setScrollLock(boolean on) { + fCtlText.setScrollLock(on); + } + + @Override + public void setInvertedColors(boolean invert) { + fCtlText.setInvertedColors(invert); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#setConnectOnEnterIfClosed(boolean) + */ + @Override + public final void setConnectOnEnterIfClosed(boolean on) { + connectOnEnterIfClosed = on; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl#isConnectOnEnterIfClosed() + */ + @Override + public final boolean isConnectOnEnterIfClosed() { + return connectOnEnterIfClosed; + } + + @Override + public void setVT100LineWrapping(boolean enable) { + getTerminalText().setVT100LineWrapping(enable); + } + + @Override + public boolean isVT100LineWrapping() { + return getTerminalText().isVT100LineWrapping(); + } + + @Override + public void enableApplicationCursorKeys(boolean enable) { + fApplicationCursorKeys = enable; + } + + @Override + public void addMouseListener(ITerminalMouseListener listener) { + getCtlText().addTerminalMouseListener(listener); + } + + @Override + public void removeMouseListener(ITerminalMouseListener listener) { + getCtlText().removeTerminalMouseListener(listener); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/ISnapshotChanges.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/ISnapshotChanges.java new file mode 100644 index 00000000000..b7c71eb9efa --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/ISnapshotChanges.java @@ -0,0 +1,92 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import org.eclipse.tm.terminal.model.ITerminalTextData; + +public interface ISnapshotChanges { + + /** + * @param line might bigger than the number of lines.... + */ + void markLineChanged(int line); + + /** + * Marks all lines in the range as changed + * @param line >=0 + * @param n might be out of range + */ + void markLinesChanged(int line, int n); + + /** + * Marks all lines within the scrolling region + * changed and resets the scrolling information + */ + void convertScrollingIntoChanges(); + + /** + * @return true if something has changed + */ + boolean hasChanged(); + + /** + * @param startLine + * @param size + * @param shift + */ + void scroll(int startLine, int size, int shift); + + /** + * Mark all lines changed + * @param height if no window is set this is the number of + * lines that are marked as changed + */ + void setAllChanged(int height); + + int getFirstChangedLine(); + + int getLastChangedLine(); + + int getScrollWindowStartLine(); + + int getScrollWindowSize(); + + int getScrollWindowShift(); + + boolean hasLineChanged(int line); + + void markDimensionsChanged(); + boolean hasDimensionsChanged(); + void markCursorChanged(); + + /** + * @return true if the terminal data has changed + */ + boolean hasTerminalChanged(); + /** + * mark the terminal as changed + */ + void setTerminalChanged(); + + + void copyChangedLines(ITerminalTextData dest, ITerminalTextData source); + + /** + * @param startLine -1 means follow the end of the data + * @param size number of lines to follow + */ + void setInterestWindow(int startLine, int size); + int getInterestWindowStartLine(); + int getInterestWindowSize(); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/SnapshotChanges.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/SnapshotChanges.java new file mode 100644 index 00000000000..0c62f59f091 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/SnapshotChanges.java @@ -0,0 +1,410 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import org.eclipse.tm.terminal.model.ITerminalTextData; + + +/** + * Collects the changes of the {@link ITerminalTextData} + * + * @noextend This class is not intended to be subclassed by clients. + * @noreference This class is not intended to be referenced by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * This class used to be package-protected. It is public only for access by the Unit Tests. + */ +public class SnapshotChanges implements ISnapshotChanges { + /** + * The first line changed + */ + private int fFirstChangedLine; + /** + * The last line changed + */ + private int fLastChangedLine; + private int fScrollWindowStartLine; + private int fScrollWindowSize; + private int fScrollWindowShift; + /** + * true, if scrolling should not tracked anymore + */ + private boolean fScrollDontTrack; + /** + * The lines that need to be copied + * into the snapshot (lines that have + * not changed don't have to be copied) + */ + private boolean[] fChangedLines; + + private int fInterestWindowSize; + private int fInterestWindowStartLine; + private boolean fDimensionsChanged; + private boolean fTerminalHasChanged; + private boolean fCursorHasChanged; + + public SnapshotChanges(int nLines) { + setChangedLinesLength(nLines); + fFirstChangedLine=Integer.MAX_VALUE; + fLastChangedLine=-1; + } + public SnapshotChanges(int windowStart, int windowSize) { + setChangedLinesLength(windowStart+windowSize); + fFirstChangedLine=Integer.MAX_VALUE; + fLastChangedLine=-1; + fInterestWindowStartLine=windowStart; + fInterestWindowSize=windowSize; + + } + /** + * This is used in asserts to throw an {@link RuntimeException}. + * This is useful for tests. + * @return never -- throws an exception + */ + private boolean throwRuntimeException() { + throw new RuntimeException(); + } + /** + * @param line + * @param size + * @return true if the range overlaps with the interest window + * @nooverride This method is not intended to be re-implemented or extended by clients. + * @noreference This method is not intended to be referenced by clients. + * It used to be package protected, and it is public only for Unit Tests. + */ + public boolean isInInterestWindow(int line, int size) { + if(fInterestWindowSize<=0) + return true; + if(line+size<=fInterestWindowStartLine || line>=fInterestWindowStartLine+fInterestWindowSize) + return false; + return true; + } + /** + * @param line + * @return true if the line is within the interest window + * @nooverride This method is not intended to be re-implemented or extended by clients. + * @noreference This method is not intended to be referenced by clients. + * It used to be package protected, and it is public only for Unit Tests. + */ + public boolean isInInterestWindow(int line) { + if(fInterestWindowSize<=0) + return true; + if(line=fInterestWindowStartLine+fInterestWindowSize) + return false; + return true; + } + /** + * @param line + * @return the line within the window + * @nooverride This method is not intended to be re-implemented or extended by clients. + * @noreference This method is not intended to be referenced by clients. + * It used to be package protected, and it is public only for Unit Tests. + */ + public int fitLineToWindow(int line) { + if(fInterestWindowSize<=0) + return line; + if(linebefore {@link #fitLineToWindow(int)} has been called! + * @param size + * @return the adjusted size. + * @nooverride This method is not intended to be re-implemented or extended by clients. + * @noreference This method is not intended to be referenced by clients. + * It used to be package protected, and it is public only for Unit Tests. + * + *

            Note:

            {@link #fitLineToWindow(int)} has to be called on the line to + * move the window correctly! + */ + public int fitSizeToWindow(int line, int size) { + if(fInterestWindowSize<=0) + return size; + if(linefInterestWindowStartLine+fInterestWindowSize) + size=fInterestWindowStartLine+fInterestWindowSize-line; + return size; + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#markLineChanged(int) + */ + public void markLineChanged(int line) { + if(!isInInterestWindow(line)) + return; + line=fitLineToWindow(line); + if(linefLastChangedLine) + fLastChangedLine=line; + // in case the terminal got resized we expand + // don't remember the changed line because + // there is nothing to copy + if(line0 || fScrollWindowShift!=0 ||fDimensionsChanged || fCursorHasChanged) + return true; + return false; + } + public void markDimensionsChanged() { + fDimensionsChanged=true; + } + public boolean hasDimensionsChanged() { + return fDimensionsChanged; + } + public boolean hasTerminalChanged() { + return fTerminalHasChanged; + } + public void setTerminalChanged() { + fTerminalHasChanged=true; + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ISnapshotChanges#scroll(int, int, int) + */ + public void scroll(int startLine, int size, int shift) { + size=fitSizeToWindow(startLine, size); + startLine=fitLineToWindow(startLine); + // let's track only negative shifts + if(fScrollDontTrack) { + // we are in a state where we cannot track scrolling + // so let's simply mark the scrolled lines as changed + markLinesChanged(startLine, size); + } else if(shift>=0) { + // we cannot handle positive scroll + // forget about clever caching of scroll events + doNotTrackScrollingAnymore(); + // mark all lines inside the scroll region as changed + markLinesChanged(startLine, size); + } else { + // we have already scrolled + if(fScrollWindowShift<0) { + // we have already scrolled + if(fScrollWindowStartLine==startLine && fScrollWindowSize==size) { + // we are scrolling the same region again? + fScrollWindowShift+=shift; + scrollChangesLinesWithNegativeShift(startLine,size,shift); + } else { + // mark all lines in the old scroll region as changed + doNotTrackScrollingAnymore(); + // mark all lines changed, because + markLinesChanged(startLine, size); + } + } else { + // first scroll in this change -- we just notify it + fScrollWindowStartLine=startLine; + fScrollWindowSize=size; + fScrollWindowShift=shift; + scrollChangesLinesWithNegativeShift(startLine,size,shift); + } + } + } + /** + * Some incompatible scrolling occurred. We cannot do the + * scroll optimization anymore... + */ + private void doNotTrackScrollingAnymore() { + if(fScrollWindowSize>0) { + // convert the current scrolling into changes + markLinesChanged(fScrollWindowStartLine, fScrollWindowSize); + fScrollWindowStartLine=0; + fScrollWindowSize=0; + fScrollWindowShift=0; + } + // don't be clever on scrolling anymore + fScrollDontTrack=true; + } + /** + * Scrolls the changed lines data + * + * @param line + * @param n + * @param shift must be negative! + */ + private void scrollChangesLinesWithNegativeShift(int line, int n, int shift) { + assert shift <0 || throwRuntimeException(); + // scroll the region + // don't run out of bounds! + int m=Math.min(line+n+shift,getChangedLineLength()+shift); + for (int i = line; i < m; i++) { + setChangedLine(i, hasLineChanged(i-shift)); + // move the first changed line up. + // We don't have to move the maximum down, + // because with a shift scroll, the max is moved + // my the next loop in this method + if(i0) { + int shift=oldStartLine-startLine; + if(shift==0) { + if(size>oldSize) { + // add lines to the end + markLinesChanged(oldStartLine+oldSize, size-oldSize); + } + // else no lines within the window have changed + + } else if(Math.abs(shift)TerminalTextData.toMultiLineText(this,0,200)) + * @param term the terminal + * @param start start line to show + * @param len number of lines to show -- negative numbers means show all + * @return a string representation of the content + */ + static public String toMultiLineText(ITerminalTextDataReadOnly term, int start, int len) { + if(len<0) + len=term.getHeight(); + StringBuffer buff=new StringBuffer(); + int width=term.getWidth(); + int n=Math.min(len,term.getHeight()-start); + for (int line = start; line < n; line++) { + if(line>0) + buff.append("\n"); //$NON-NLS-1$ + for (int column = 0; column < width; column++) { + buff.append(term.getChar(line, column)); + } + } + // get rid of the empty space at the end of the lines + //return buff.toString().replaceAll("\000+", ""); //$NON-NLS-1$//$NON-NLS-2$ + // + int i = buff.length() - 1; + while (i >= 0 && buff.charAt(i) == '\000') { + i--; + } + buff.setLength(i + 1); + return buff.toString(); + // + } + + /** + * Show the first 100 lines + * see {@link #toMultiLineText(ITerminalTextDataReadOnly, int, int)} + * @param term A read-only terminal model + * @return a string representation of the terminal + */ + static public String toMultiLineText(ITerminalTextDataReadOnly term) { + return toMultiLineText(term, 0, 100); + } + + public TerminalTextData() { + this(new TerminalTextDataFastScroll()); + +// this(new TerminalTextDataStore()); + } + public TerminalTextData(ITerminalTextData data) { + fData=data; + } + public int getWidth() { + return fData.getWidth(); + } + public int getHeight() { + // no need for an extra variable + return fData.getHeight(); + } + public void setDimensions(int height, int width) { + int h=getHeight(); + int w=getWidth(); + if(w==width && h==height) + return; + fData.setDimensions(height, width); + sendDimensionsChanged(h, w, height, width); + } + private void sendDimensionsChanged(int oldHeight, int oldWidth, int newHeight, int newWidth) { + // determine what has changed + if(oldWidth==newWidth) { + if(oldHeight list=new ArrayList(); + list.addAll(Arrays.asList(fSnapshots)); + list.remove(snapshot); + fSnapshots=list.toArray(new TerminalTextDataSnapshot[list.size()]); + } + + public ITerminalTextDataSnapshot makeSnapshot() { + // poor mans approach to modify the array + TerminalTextDataSnapshot snapshot=new TerminalTextDataSnapshot(this); + snapshot.markDimensionsChanged(); + List list=new ArrayList(); + list.addAll(Arrays.asList(fSnapshots)); + list.add(snapshot); + fSnapshots=list.toArray(new TerminalTextDataSnapshot[list.size()]); + return snapshot; + } + public void addLine() { + int oldHeight=getHeight(); + fData.addLine(); + // was is an append or a scroll? + int newHeight=getHeight(); + if(newHeight>oldHeight) { + //the line was appended + sendLinesChangedToSnapshot(oldHeight, 1); + int width=getWidth(); + sendDimensionsChanged(oldHeight, width, newHeight, width); + + } else { + // the line was scrolled + sendScrolledToSnapshots(0, oldHeight, -1); + } + + } + + public void copy(ITerminalTextData source) { + fData.copy(source); + fCursorLine=source.getCursorLine(); + fCursorColumn=source.getCursorColumn(); + } + + public void copyLine(ITerminalTextData source, int sourceLine, int destLine) { + fData.copyLine(source, sourceLine, destLine); + } + public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine, int length) { + fData.copyRange(source, sourceStartLine, destStartLine, length); + } + public char[] getChars(int line) { + return fData.getChars(line); + } + public Style[] getStyles(int line) { + return fData.getStyles(line); + } + public int getMaxHeight() { + return fData.getMaxHeight(); + } + public void setMaxHeight(int height) { + fData.setMaxHeight(height); + } + public void cleanLine(int line) { + fData.cleanLine(line); + sendLineChangedToSnapshots(line); + } + public int getCursorColumn() { + return fCursorColumn; + } + public int getCursorLine() { + return fCursorLine; + } + public void setCursorColumn(int column) { + fCursorColumn=column; + sendCursorChanged(); + } + public void setCursorLine(int line) { + fCursorLine=line; + sendCursorChanged(); + } + + public boolean isWrappedLine(int line) { + return fData.isWrappedLine(line); + } + + public void setWrappedLine(int line) { + fData.setWrappedLine(line); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataFastScroll.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataFastScroll.java new file mode 100644 index 00000000000..e175cd7182c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataFastScroll.java @@ -0,0 +1,259 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; +import org.eclipse.tm.terminal.model.LineSegment; +import org.eclipse.tm.terminal.model.Style; + +/** + * This class is optimized for scrolling the entire {@link #getHeight()}. + * The scrolling is done by moving an offset into the data and using + * the modulo operator. + * + */ +public class TerminalTextDataFastScroll implements ITerminalTextData { + + final ITerminalTextData fData; + private int fHeight; + private int fMaxHeight; + /** + * The offset into the array. + */ + int fOffset; + public TerminalTextDataFastScroll(ITerminalTextData data,int maxHeight) { + fMaxHeight=maxHeight; + fData=data; + fData.setDimensions(maxHeight, fData.getWidth()); + if(maxHeight>2) + assert shiftOffset(-2) || throwRuntimeException(); + } + public TerminalTextDataFastScroll(int maxHeight) { + this(new TerminalTextDataStore(),maxHeight); + } + public TerminalTextDataFastScroll() { + this(new TerminalTextDataStore(),1); + } + /** + * This is used in asserts to throw an {@link RuntimeException}. + * This is useful for tests. + * @return never -- throws an exception + */ + private boolean throwRuntimeException() { + throw new RuntimeException(); + } + /** + * + * @param line + * @return the actual line number in {@link #fData} + */ + int getPositionOfLine(int line) { + return (line+fOffset)%fMaxHeight; + } + /** + * Moves offset by delta. This does not move the data! + * @param delta + */ + void moveOffset(int delta) { + assert Math.abs(delta)=0 && destStartLine+length<=fHeight) || throwRuntimeException(); + for (int i = 0; i < length; i++) { + fData.copyLine(source, i+sourceStartLine, getPositionOfLine(i+destStartLine)); + } + } + + public char getChar(int line, int column) { + assert (line>=0 && line=0 && line=0 && line=0 && line=0 && line=0 && startLine+size<=fHeight) || throwRuntimeException(); + if(shift>=fMaxHeight || -shift>=fMaxHeight) { + cleanLines(startLine, fMaxHeight-startLine); + return; + } + if(size==fHeight) { + // This is the case this class is optimized for! + moveOffset(-shift); + // we only have to clean the lines that appear by the move + if(shift<0) { + cleanLines(Math.max(startLine, startLine+size+shift),Math.min(-shift, getHeight()-startLine)); + } else { + cleanLines(startLine, Math.min(shift, getHeight()-startLine)); + } + } else { + // we have to copy the lines. + if(shift<0) { + // move the region up + // shift is negative!! + for (int i = startLine; i < startLine+size+shift; i++) { + fData.copyLine(fData, getPositionOfLine(i-shift), getPositionOfLine(i)); + } + // then clean the opened lines + cleanLines(Math.max(0, startLine+size+shift),Math.min(-shift, getHeight()-startLine)); + } else { + for (int i = startLine+size-1; i >=startLine && i-shift>=0; i--) { + fData.copyLine(fData, getPositionOfLine(i-shift), getPositionOfLine(i)); + } + cleanLines(startLine, Math.min(shift, getHeight()-startLine)); + } + } + } + + public void setChar(int line, int column, char c, Style style) { + assert (line>=0 && line=0 && line=0 && line=0 || throwRuntimeException(); + assert width>=0 || throwRuntimeException(); + if(height > fMaxHeight) + setMaxHeight(height); + fHeight=height; + if(width!=fData.getWidth()) + fData.setDimensions(fMaxHeight, width); + } + + public void setMaxHeight(int maxHeight) { + assert maxHeight>=fHeight || throwRuntimeException(); + // move everything to offset0 + int start=getPositionOfLine(0); + if(start!=0) { + // invent a more efficient algorithm.... + ITerminalTextData buffer=new TerminalTextDataStore(); + // create a buffer with the expected height + buffer.setDimensions(maxHeight, getWidth()); + int n=Math.min(fMaxHeight-start,maxHeight); + // copy the first part + buffer.copyRange(fData, start, 0, n); + // copy the second part + if(n=0 && line=0 && linenot threadsafe! + */ +class TerminalTextDataSnapshot implements ITerminalTextDataSnapshot { + /** + * The changes of the current snapshot relative to the + * previous snapshot + */ + volatile ISnapshotChanges fCurrentChanges; + /** + * Keeps track of changes that happened since the current + * snapshot has been made. + */ + ISnapshotChanges fFutureChanges; + /** + * Is used as lock and is the reference to the terminal we take snapshots from. + */ + final TerminalTextData fTerminal; + /** + * A snapshot copy of of fTerminal + */ + // snapshot does not need internal synchronisation + final TerminalTextDataWindow fSnapshot; + // this variable is synchronized on fTerminal! + private SnapshotOutOfDateListener[] fListener=new SnapshotOutOfDateListener[0]; + // this variable is synchronized on fTerminal! + private boolean fListenersNeedNotify; + private int fInterestWindowSize; + private int fInterestWindowStartLine; + + TerminalTextDataSnapshot(TerminalTextData terminal) { + fSnapshot = new TerminalTextDataWindow(); + fTerminal = terminal; + fCurrentChanges = new SnapshotChanges(fTerminal.getHeight()); + fCurrentChanges.setTerminalChanged(); + fFutureChanges = new SnapshotChanges(fTerminal.getHeight()); + fFutureChanges.markLinesChanged(0, fTerminal.getHeight()); + fListenersNeedNotify=true; + fInterestWindowSize=-1; + } + /** + * This is used in asserts to throw an {@link RuntimeException}. + * This is useful for tests. + * @return never -- throws an exception + */ + private boolean throwRuntimeException() { + throw new RuntimeException(); + } + + public void detach() { + fTerminal.removeSnapshot(this); + } + + public boolean isOutOfDate() { + // this is called from fTerminal, therefore we lock on fTerminal + synchronized (fTerminal) { + return fFutureChanges.hasChanged(); + } + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#snapshot() + */ + public void updateSnapshot(boolean detectScrolling) { + // make sure terminal does not change while we make the snapshot + synchronized (fTerminal) { + // let's make the future changes current + fCurrentChanges=fFutureChanges; + fFutureChanges=new SnapshotChanges(fTerminal.getHeight()); + fFutureChanges.setInterestWindow(fInterestWindowStartLine, fInterestWindowSize); + // and update the snapshot + if(fSnapshot.getHeight()!=fTerminal.getHeight()||fSnapshot.getWidth()!=fTerminal.getWidth()) { + if(fInterestWindowSize==-1) + fSnapshot.setWindow(0, fTerminal.getHeight()); + // if the dimensions have changed, we need a full copy + fSnapshot.copy(fTerminal); + // and we mark all lines as changed + fCurrentChanges.setAllChanged(fTerminal.getHeight()); + } else { + // first we do the scroll on the copy + int start=fCurrentChanges.getScrollWindowStartLine(); + int lines=Math.min(fCurrentChanges.getScrollWindowSize(), fSnapshot.getHeight()-start); + fSnapshot.scroll(start, lines, fCurrentChanges.getScrollWindowShift()); + // and then create the snapshot of the changed lines + fCurrentChanges.copyChangedLines(fSnapshot, fTerminal); + } + fListenersNeedNotify=true; + fSnapshot.setCursorLine(fTerminal.getCursorLine()); + fSnapshot.setCursorColumn(fTerminal.getCursorColumn()); + } + if(!detectScrolling) { + // let's pretend there was no scrolling and + // convert the scrolling into line changes + fCurrentChanges.convertScrollingIntoChanges(); + } + } + + public char getChar(int line, int column) { + return fSnapshot.getChar(line, column); + } + + public int getHeight() { + return fSnapshot.getHeight(); + } + + public LineSegment[] getLineSegments(int line, int column, int len) { + return fSnapshot.getLineSegments(line, column, len); + } + + public Style getStyle(int line, int column) { + return fSnapshot.getStyle(line, column); + } + + public int getWidth() { + return fSnapshot.getWidth(); + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getFirstChangedLine() + */ + public int getFirstChangedLine() { + return fCurrentChanges.getFirstChangedLine(); + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getLastChangedLine() + */ + public int getLastChangedLine() { + return fCurrentChanges.getLastChangedLine(); + } + + public boolean hasLineChanged(int line) { + return fCurrentChanges.hasLineChanged(line); + } + public boolean hasDimensionsChanged() { + return fCurrentChanges.hasDimensionsChanged(); + } + public boolean hasTerminalChanged() { + return fCurrentChanges.hasTerminalChanged(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getScrollChangeY() + */ + public int getScrollWindowStartLine() { + return fCurrentChanges.getScrollWindowStartLine(); + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getScrollChangeN() + */ + public int getScrollWindowSize() { + return fCurrentChanges.getScrollWindowSize(); + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.model.ITerminalTextDataSnapshot#getScrollChangeShift() + */ + public int getScrollWindowShift() { + return fCurrentChanges.getScrollWindowShift(); + } + + /** + * Announces a change in line line + * @param line + */ + void markLineChanged(int line) { + // threading + fFutureChanges.markLineChanged(line); + fFutureChanges.setTerminalChanged(); + notifyListers(); + } + /** + * Announces a change of n lines beginning with line line + * @param line + * @param n + */ + void markLinesChanged(int line,int n) { + fFutureChanges.markLinesChanged(line,n); + fFutureChanges.setTerminalChanged(); + notifyListers(); + } + + void markDimensionsChanged() { + fFutureChanges.markDimensionsChanged(); + fFutureChanges.setTerminalChanged(); + notifyListers(); + } + void markCursorChanged() { + fFutureChanges.markCursorChanged(); + fFutureChanges.setTerminalChanged(); + notifyListers(); + } + + /** + * @param startLine + * @param size + * @param shift + */ + void scroll(int startLine, int size, int shift) { + fFutureChanges.scroll(startLine,size,shift); + fFutureChanges.setTerminalChanged(); + notifyListers(); + } + /** + * Notifies listeners about the change + */ + private void notifyListers() { + // this code has to be called from a block synchronized on fTerminal + synchronized (fTerminal) { + if(fListenersNeedNotify) { + for (int i = 0; i < fListener.length; i++) { + fListener[i].snapshotOutOfDate(this); + } + fListenersNeedNotify=false; + } + } + } + public ITerminalTextDataSnapshot makeSnapshot() { + return fSnapshot.makeSnapshot(); + } + + synchronized public void addListener(SnapshotOutOfDateListener listener) { + List list=new ArrayList(); + list.addAll(Arrays.asList(fListener)); + list.add(listener); + fListener=list.toArray(new SnapshotOutOfDateListener[list.size()]); + } + + synchronized public void removeListener(SnapshotOutOfDateListener listener) { + List list=new ArrayList(); + list.addAll(Arrays.asList(fListener)); + list.remove(listener); + fListener=list.toArray(new SnapshotOutOfDateListener[list.size()]); + } + public String toString() { + return fSnapshot.toString(); + } + + + public int getInterestWindowSize() { + return fInterestWindowSize; + } + + + public int getInterestWindowStartLine() { + return fInterestWindowStartLine; + } + + public void setInterestWindow(int startLine, int size) { + assert startLine>=0 || throwRuntimeException(); + assert size>=0 || throwRuntimeException(); + fInterestWindowStartLine=startLine; + fInterestWindowSize=size; + fSnapshot.setWindow(startLine, size); + fFutureChanges.setInterestWindow(startLine, size); + notifyListers(); + } + + + public char[] getChars(int line) { + return fSnapshot.getChars(line); + } + + + public Style[] getStyles(int line) { + return fSnapshot.getStyles(line); + } + public int getCursorColumn() { + return fSnapshot.getCursorColumn(); + } + public int getCursorLine() { + return fSnapshot.getCursorLine(); + } + public ITerminalTextData getTerminalTextData() { + return fTerminal; + } + public boolean isWrappedLine(int line) { + return fSnapshot.isWrappedLine(line); + } +} + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataStore.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataStore.java new file mode 100644 index 00000000000..280a28d7cdf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataStore.java @@ -0,0 +1,344 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.BitSet; +import java.util.List; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; +import org.eclipse.tm.terminal.model.LineSegment; +import org.eclipse.tm.terminal.model.Style; + +/** + * This class is thread safe. + * + */ +public class TerminalTextDataStore implements ITerminalTextData { + private char[][] fChars; + private Style[][] fStyle; + private int fWidth; + private int fHeight; + private int fMaxHeight; + private int fCursorColumn; + private int fCursorLine; + final private BitSet fWrappedLines = new BitSet(); + + public TerminalTextDataStore() { + fChars=new char[0][]; + fStyle=new Style[0][]; + fWidth=0; + } + /** + * This is used in asserts to throw an {@link RuntimeException}. + * This is useful for tests. + * @return never -- throws an exception + */ + private boolean throwRuntimeException() { + throw new RuntimeException(); + } + + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getWidth() + */ + public int getWidth() { + return fWidth; + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getHeight() + */ + public int getHeight() { + return fHeight; + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#setDimensions(int, int) + */ + public void setDimensions(int height, int width) { + assert height>=0 || throwRuntimeException(); + assert width>=0 || throwRuntimeException(); + // just extend the region + if(height>fChars.length) { + int h=4*height/3; + if(fMaxHeight>0 && h>fMaxHeight) + h=fMaxHeight; + fStyle=(Style[][]) resizeArray(fStyle, height); + fChars=(char[][]) resizeArray(fChars, height); + } + // clean the new lines + if(height>fHeight) { + for (int i = fHeight; i < height; i++) { + cleanLine(i); + } + } + // set dimensions after successful resize! + fWidth=width; + fHeight=height; + } + /** + * Reallocates an array with a new size, and copies the contents of the old + * array to the new array. + * + * @param origArray the old array, to be reallocated. + * @param newSize the new array size. + * @return A new array with the same contents (chopped off if needed or filled with 0 or null). + */ + private Object resizeArray(Object origArray, int newSize) { + int oldSize = Array.getLength(origArray); + if(oldSize==newSize) + return origArray; + Class elementType = origArray.getClass().getComponentType(); + Object newArray = Array.newInstance(elementType, newSize); + int preserveLength = Math.min(oldSize, newSize); + if (preserveLength > 0) + System.arraycopy(origArray, 0, newArray, 0, preserveLength); + return newArray; + } + + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getLineSegments(int, int, int) + */ + public LineSegment[] getLineSegments(int line, int column, int len) { + // get the styles and chars for this line + Style[] styles=fStyle[line]; + char[] chars=fChars[line]; + int col=column; + int n=column+len; + + // expand the line if needed.... + if(styles==null) + styles=new Style[n]; + else if(styles.length segments=new ArrayList(); + for (int i = column; i < n; i++) { + if(styles[i]!=style) { + segments.add(new LineSegment(col,new String(chars,col,i-col),style)); + style=styles[i]; + col=i; + } + } + if(col < n) { + segments.add(new LineSegment(col,new String(chars,col,n-col),style)); + } + return segments.toArray(new LineSegment[segments.size()]); + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getChar(int, int) + */ + public char getChar(int line, int column) { + assert column=fChars[line].length) + return 0; + return fChars[line][column]; + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.text.ITerminalTextData#getStyle(int, int) + */ + public Style getStyle(int line, int column) { + assert column=fStyle[line].length) + return null; + return fStyle[line][column]; + } + + void ensureLineLength(int iLine, int length) { + if(length>fWidth) + throw new RuntimeException(); + if(fChars[iLine]==null) { + fChars[iLine]=new char[length]; + } else if(fChars[iLine].length=startLine && i-shift>=0; i--) { + fChars[i]=fChars[i-shift]; + fStyle[i]=fStyle[i-shift]; + fWrappedLines.set(i, fWrappedLines.get(i-shift)); + } + cleanLines(startLine, Math.min(shift, getHeight()-startLine)); + } + } + /** + * Replaces the lines with new empty data + * @param line + * @param len + */ + private void cleanLines(int line, int len) { + for (int i = line; i < line+len; i++) { + cleanLine(i); + } + } + + /* + * @return a text representation of the object. + * Lines are separated by '\n'. No style information is returned. + */ + public String toString() { + StringBuffer buff=new StringBuffer(); + for (int line = 0; line < getHeight(); line++) { + if(line>0) + buff.append("\n"); //$NON-NLS-1$ + for (int column = 0; column < fWidth; column++) { + buff.append(getChar(line, column)); + } + } + return buff.toString(); + } + + + public ITerminalTextDataSnapshot makeSnapshot() { + throw new UnsupportedOperationException(); + } + + public void addLine() { + if(fMaxHeight>0 && getHeight()char=='\000' and style=null. + * + */ +public class TerminalTextDataWindow implements ITerminalTextData { + final ITerminalTextData fData; + int fWindowStartLine; + int fWindowSize; + int fHeight; + int fMaxHeight; + public TerminalTextDataWindow(ITerminalTextData data) { + fData=data; + } + public TerminalTextDataWindow() { + this(new TerminalTextDataStore()); + } + /** + * This is used in asserts to throw an {@link RuntimeException}. + * This is useful for tests. + * @return never -- throws an exception + */ + private boolean throwRuntimeException() { + throw new RuntimeException(); + } + /** + * @param line + * @return true if the line is within the window + */ + boolean isInWindow(int line) { + return line>=fWindowStartLine && line0 && getHeight()0) + fData.copyRange(source, fWindowStartLine, 0, n); + } + public void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine, int length) { + int n=length; + int dStart=destStartLine-fWindowStartLine; + int sStart=sourceStartLine; + // if start outside our range, cut the length to copy + if(dStart<0) { + n+=dStart; + sStart-=dStart; + dStart=0; + } + // do not exceed the window size + n=Math.min(n,fWindowSize); + if(n>0) + fData.copyRange(source, sStart, dStart, n); + + } + public void copyLine(ITerminalTextData source, int sourceLine, int destLine) { + if(isInWindow(destLine)) + fData.copyLine(source, sourceLine, destLine-fWindowStartLine); + } + public void scroll(int startLine, int size, int shift) { + assert (startLine>=0 && startLine+size<=fHeight) || throwRuntimeException(); + int n=size; + int start=startLine-fWindowStartLine; + // if start outside our range, cut the length to copy + if(start<0) { + n+=start; + start=0; + } + n=Math.min(n,fWindowSize-start); + // do not exceed the window size + if(n>0) + fData.scroll(start, n, shift); + } + public void setChar(int line, int column, char c, Style style) { + if(!isInWindow(line)) + return; + fData.setChar(line-fWindowStartLine, column, c, style); + } + public void setChars(int line, int column, char[] chars, int start, int len, Style style) { + if(!isInWindow(line)) + return; + fData.setChars(line-fWindowStartLine, column, chars, start, len, style); + } + public void setChars(int line, int column, char[] chars, Style style) { + if(!isInWindow(line)) + return; + fData.setChars(line-fWindowStartLine, column, chars, style); + } + public void setDimensions(int height, int width) { + assert height>=0 || throwRuntimeException(); + fData.setDimensions(fWindowSize, width); + fHeight=height; + } + public void setMaxHeight(int height) { + fMaxHeight=height; + } + public void setWindow(int startLine, int size) { + fWindowStartLine=startLine; + fWindowSize=size; + fData.setDimensions(fWindowSize, getWidth()); + } + public int getWindowStartLine() { + return fWindowStartLine; + } + public int getWindowSize() { + return fWindowSize; + } + public void setHeight(int height) { + fHeight = height; + } + public void cleanLine(int line) { + if(isInWindow(line)) + fData.cleanLine(line-fWindowStartLine); + } + public int getCursorColumn() { + return fData.getCursorColumn(); + } + public int getCursorLine() { + return fData.getCursorLine(); + } + public void setCursorColumn(int column) { + fData.setCursorColumn(column); + } + public void setCursorLine(int line) { + fData.setCursorLine(line); + } + public boolean isWrappedLine(int line) { + if(isInWindow(line)) + return fData.isWrappedLine(line - fWindowStartLine); + return false; + } + public void setWrappedLine(int line) { + if(isInWindow(line)) + fData.setWrappedLine(line - fWindowStartLine); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/ITerminalConstants.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/ITerminalConstants.java new file mode 100644 index 00000000000..b9980eec90b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/ITerminalConstants.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.preferences; + +/** + * Constants for Terminal Preferences. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITerminalConstants { + + public static final String PREF_HAS_MIGRATED = "TerminalPref.migrated"; //$NON-NLS-1$ + + public static final String PREF_BUFFERLINES = "TerminalPrefBufferLines"; //$NON-NLS-1$ + public static final String PREF_INVERT_COLORS = "TerminalPrefInvertColors"; //$NON-NLS-1$ + public static final int DEFAULT_BUFFERLINES = 1000; + public static final boolean DEFAULT_INVERT_COLORS = false; + + public static final String FONT_DEFINITION = "terminal.views.view.font.definition"; //$NON-NLS-1$ + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/TerminalPreferenceInitializer.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/TerminalPreferenceInitializer.java new file mode 100644 index 00000000000..431dd902d3b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/TerminalPreferenceInitializer.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget + * Martin Oberhuber (Wind River) - [436612] Restore Eclipse 3.4 compatibility + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin; + +/** + * Terminal Preference Initializer. + * + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * @noreference This class is not intended to be referenced by clients. + */ +public class TerminalPreferenceInitializer extends AbstractPreferenceInitializer { + + public TerminalPreferenceInitializer() { + } + + public void initializeDefaultPreferences() { + //DefaultScope.INSTANCE was added in Eclipse 3.7 + IEclipsePreferences defaultPrefs = DefaultScope.INSTANCE.getNode(TerminalPlugin.PLUGIN_ID); + defaultPrefs.putBoolean(ITerminalConstants.PREF_INVERT_COLORS, ITerminalConstants.DEFAULT_INVERT_COLORS); + defaultPrefs.putInt(ITerminalConstants.PREF_BUFFERLINES, ITerminalConstants.DEFAULT_BUFFERLINES); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/TerminalPreferencePage.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/TerminalPreferencePage.java new file mode 100644 index 00000000000..7bb452c5855 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/preferences/TerminalPreferencePage.java @@ -0,0 +1,77 @@ +/******************************************************************************* + * Copyright (c) 2003, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Initial Contributors: + * The following Wind River employees contributed to the Terminal component + * that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, + * Helmut Haigermoser and Ted Williams. + * + * Contributors: + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [378691][api] push Preferences into the Widget + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.preferences; + +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.tm.internal.terminal.control.impl.TerminalMessages; +import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; + +/** + * Terminal Preference Page. + * + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * @noreference This class is not intended to be referenced by clients. + */ +public class TerminalPreferencePage extends FieldEditorPreferencePage implements + IWorkbenchPreferencePage { + protected BooleanFieldEditor fInvertColors; + + protected IntegerFieldEditor fEditorBufferSize; + + public TerminalPreferencePage() { + super(GRID); + } + protected void createFieldEditors() { + setupPage(); + } + public void init(IWorkbench workbench) { + // do nothing + } + protected void setupPage() { + setupData(); + setupEditors(); + } + protected void setupData() { + TerminalPlugin plugin; + IPreferenceStore preferenceStore; + + plugin = TerminalPlugin.getDefault(); + preferenceStore = plugin.getPreferenceStore(); + setPreferenceStore(preferenceStore); + } + protected void setupEditors() { + fInvertColors = new BooleanFieldEditor( + ITerminalConstants.PREF_INVERT_COLORS, TerminalMessages.INVERT_COLORS, + getFieldEditorParent()); + fEditorBufferSize = new IntegerFieldEditor(ITerminalConstants.PREF_BUFFERLINES, + TerminalMessages.BUFFERLINES, getFieldEditorParent()); + + fEditorBufferSize.setValidRange(0, Integer.MAX_VALUE); + + addField(fInvertColors); + addField(fEditorBufferSize); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/AbstractSettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/AbstractSettingsPage.java new file mode 100644 index 00000000000..673716e8267 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/AbstractSettingsPage.java @@ -0,0 +1,183 @@ +/******************************************************************************* + * Copyright (c) 2013, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.fieldassist.ControlDecoration; +import org.eclipse.jface.fieldassist.FieldDecoration; +import org.eclipse.jface.fieldassist.FieldDecorationRegistry; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Control; + +/** + * Abstract settings page providing a common implementation of the listener handling. + */ +public abstract class AbstractSettingsPage implements ISettingsPage, IMessageProvider { + // A message associated with the control. + private String message = null; + + // The message type of the associated message. + private int messageType = IMessageProvider.NONE; + + // Reference to the listener + private final ListenerList listeners = new ListenerList(); + + // Flag to control the control decorations + private boolean hasDecoration = false; + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#addListener(org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage.Listener) + */ + public void addListener(Listener listener) { + Assert.isNotNull(listener); + listeners.add(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#removeListener(org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage.Listener) + */ + public void removeListener(Listener listener) { + Assert.isNotNull(listener); + listeners.remove(listener); + } + + /** + * Fire the listeners for the given control. + * + * @param control The control or null. + */ + public void fireListeners(Control control) { + Object[] list = listeners.getListeners(); + for (int i = 0; i < list.length; i++) { + Object l = list[i]; + if (!(l instanceof Listener)) continue; + ((Listener)l).onSettingsPageChanged(control); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessage() + */ + public final String getMessage() { + return message; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessageType() + */ + public final int getMessageType() { + return messageType; + } + + /** + * Set the message and the message type. + * + * @param message The message or null. + * @param messageType The type of the message (NONE, INFORMATION, WARNING, ERROR). + */ + public final void setMessage(String message, int messageType) { + this.message = message; + this.messageType = messageType; + } + + /** + * Sets if or if not the settings panel widgets will have control decorations + * or not. The method has effect only if called before {@link #createControl(org.eclipse.swt.widgets.Composite)}. + * + * @param value True if the panel widgets have control decorations, false otherwise. + */ + public final void setHasControlDecoration(boolean value) { + this.hasDecoration = value; + } + + /** + * Returns if or if not the settings panel widgets will have control + * decorations or not. + * + * @return True if the panel widgets have control decorations, false otherwise. + */ + protected final boolean hasControlDecoration() { + return hasDecoration; + } + + /** + * Creates a new instance of a {@link ControlDecoration} object associated with + * the given control. The method is called after the control has been created. + * + * @param control The control. Must not be null. + * @return The control decoration object instance. + */ + protected final ControlDecoration createControlDecoration(Control control) { + Assert.isNotNull(control); + if (!hasDecoration) return null; + ControlDecoration controlDecoration = new ControlDecoration(control, getControlDecorationPosition()); + controlDecoration.setShowOnlyOnFocus(false); + control.setData("controlDecoration", controlDecoration); //$NON-NLS-1$ + return controlDecoration; + } + + /** + * Returns the control decoration position. The default is + * {@link SWT#TOP} | {@link SWT#LEFT}. + * + * @return The control position. + */ + protected int getControlDecorationPosition() { + return SWT.TOP | SWT.LEFT; + } + + /** + * Updates the control decoration of the given control to represent the given message + * and message type. If the message is null or the message type is + * {@link IMessageProvider#NONE} no decoration will be shown. + * + * @param control The control. Must not be null. + * @param message The message. + * @param messageType The message type. + */ + protected final void updateControlDecoration(Control control, String message, int messageType) { + Assert.isNotNull(control); + + ControlDecoration controlDecoration = (ControlDecoration)control.getData("controlDecoration"); //$NON-NLS-1$ + if (controlDecoration != null) { + // The description is the same as the message + controlDecoration.setDescriptionText(message); + + // The icon depends on the message type + FieldDecorationRegistry registry = FieldDecorationRegistry.getDefault(); + + // Determine the id of the decoration to show + String decorationId = FieldDecorationRegistry.DEC_INFORMATION; + if (messageType == IMessageProvider.ERROR) { + decorationId = FieldDecorationRegistry.DEC_ERROR; + } else if (messageType == IMessageProvider.WARNING) { + decorationId = FieldDecorationRegistry.DEC_WARNING; + } + + // Get the field decoration + FieldDecoration fieldDeco = registry.getFieldDecoration(decorationId); + if (fieldDeco != null) { + controlDecoration.setImage(fieldDeco.getImage()); + } + + if (message == null || messageType == IMessageProvider.NONE) { + controlDecoration.hide(); + } + else { + controlDecoration.show(); + } + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ISettingsPage.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ISettingsPage.java new file mode 100644 index 00000000000..33e895a0578 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ISettingsPage.java @@ -0,0 +1,82 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; + +/** + * @author Michael Scharf + * + * TODO: Michael Scharf: provide a long description of a wizard + * TODO: Michael Scharf: allow multiple pages to be generated + *

            + * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the Target Management team. + *

            + */ +public interface ISettingsPage { + + public interface Listener { + + /** + * Invoked by settings page controls to signal that the settings page + * changed and page container may update their state. + * + * @param control The control which triggered the event or null + */ + public void onSettingsPageChanged(Control control); + } + + /** + * 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(); + + /** + * Adds the given listener. + *

            + * Has not effect if the same listener is already registered. + * + * @param listener The listener. Must not be null. + */ + public void addListener(Listener listener); + + /** + * Removes the given listener. + *

            + * Has no effect if the same listener was not registered. + * + * @param listener The listener. Must not be null. + */ + public void removeListener(Listener listener); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ISettingsStore.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ISettingsStore.java new file mode 100644 index 00000000000..7346453b4cc --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ISettingsStore.java @@ -0,0 +1,45 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +/** + * A simple interface to a store to persist the state of a connection. + * + * @author Michael Scharf + *

            + * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the Target Management team. + *

            + */ +public interface ISettingsStore { + /** + * @param key alpha numeric key, may contain dots (.) + * @return value + */ + String get(String key); + + /** + * @param key alpha numeric key, may contain dots (.) + * @param defaultValue + * @return the value or the default + */ + String get(String key, String defaultValue); + + /** + * Save a string value + * @param key alpha numeric key, may contain dots (.) + * @param value + */ + void put(String key, String value); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalConnector.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalConnector.java new file mode 100644 index 00000000000..244fb9ab7fb --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalConnector.java @@ -0,0 +1,149 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [261486][api][cleanup] Mark @noimplement interfaces as @noextend + * Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +import java.io.OutputStream; + +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +/** + * A contributed connection type to manage a single connection. + * + * Implementations of this class are contributed through the + * org.eclipse.tm.terminal.control.connectors extension point. This + * class gives access to the static markup of a terminal connector extension as + * well as providing the lifecycle management for the dynamically loaded + * {@link TerminalConnectorImpl} instance, which performs the actual + * communications. This pattern allows for lazy initialization, bundle + * activation and class loading of the actual {@link TerminalConnectorImpl} + * instance. + * + * Clients can get terminal connector instances from the + * {@link TerminalConnectorExtension} class, or from + * {@link ITerminalViewControl#getTerminalConnector()} when running inside an + * active terminal widget. + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + * + * @author Michael Scharf + *

            + * EXPERIMENTAL. This class or interface has been added + * as part of a work in progress. There is no guarantee that this API + * will work or that it will remain the same. Please do not use this API + * without consulting with the Target Management team. + *

            + */ +public interface ITerminalConnector extends IAdaptable { + /** + * @return an ID of this connector. The id from the plugin.xml. + * @since org.eclipse.tm.terminal 2.0 + */ + String getId(); + + /** + * @return null the name (as specified in the plugin.xml) + * @since org.eclipse.tm.terminal 2.0 + */ + String getName(); + + /** + * @return True if the connector is not visible in user + * selections. + * @since org.eclipse.tm.terminal 3.0.1 + */ + boolean isHidden(); + + /** + * @return true if the {@link TerminalConnectorImpl} has been initialized. + * If there was an initialization error, {@link #getInitializationErrorMessage()} + * returns the error message. + * @since org.eclipse.tm.terminal 2.0 + */ + boolean isInitialized(); + + /** + * This method initializes the connector if it is not initialized! + * If the connector was initialized successfully, null is + * returned. Otherwise an error message describing the problem is returned. + * @return null or a localized error message. + * @since org.eclipse.tm.terminal 2.0 + */ + String getInitializationErrorMessage(); + + /** + * 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 the terminal to remote stream (bytes written to this stream will + * be sent to the remote site). For the stream in the other direction (remote to + * terminal see {@link ITerminalControl#getRemoteToTerminalOutputStream()} + * @since org.eclipse.tm.terminal 2.0 + */ + OutputStream getTerminalToRemoteStream(); + + /** + * 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 connection. + */ + 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); + + /** + * Set or reset the settings store to the default values. + */ + void setDefaultSettings(); + + /** + * @return A string that represents the settings of the connection. This representation + * may be shown in the status line of the terminal view. + */ + String getSettingsSummary(); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java new file mode 100644 index 00000000000..ac133ffdb5c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/ITerminalControl.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Martin Oberhuber (Wind River) - [204796] Terminal should allow setting the encoding to use + * Martin Oberhuber (Wind River) - [261486][api][cleanup] Mark @noimplement interfaces as @noextend + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; + +/** + * Represents the terminal view as seen by a terminal connection. + *

            + * EXPERIMENTAL. This class or interface has been added as part + * of a work in progress. There is no guarantee that this API will work or that + * it will remain the same. Please do not use this API without consulting with + * the Target Management team. + *

            + * + * @author Michael Scharf + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ITerminalControl { + + /** + * @return the current state of the connection + */ + TerminalState getState(); + + /** + * @param state + */ + void setState(TerminalState state); + + /** + * Setup the terminal control within the given parent composite. + * + * @param parent The parent composite. Must not be null. + */ + void setupTerminal(Composite parent); + + /** + * A shell to show dialogs. + * @return the shell in which the terminal is shown. + */ + Shell getShell(); + + /** + * Set the encoding that the Terminal uses to decode bytes from the + * Terminal-to-remote-Stream into Unicode Characters used in Java; or, to + * encode Characters typed by the user into bytes sent over the wire to the + * remote. + * + * By default, the local Platform Default Encoding is used. Also note that + * the encoding must not be applied in case the terminal stream is processed + * by some data transfer protocol which requires binary data. + * + * Validity of the encoding set here is not checked. Since some encodings do + * not cover the entire range of Unicode characters, it can happen that a + * particular Unicode String typed in by the user can not be encoded into a + * byte Stream with the encoding specified. and UnsupportedEncodingException + * will be thrown in this case at the time the String is about to be + * processed. + * + * The concrete encoding to use can either be specified manually by a user, + * by means of a dialog, or a connector can try to obtain it automatically + * from the remote side e.g. by evaluating an environment variable such as + * LANG on UNIX systems. + * + * @since org.eclipse.tm.terminal 2.0 + */ + void setEncoding(String encoding) throws UnsupportedEncodingException; + + /** + * Return the current encoding. That's interesting when the previous + * setEncoding() call failed and the fallback default encoding should be + * queried, such that e.g. a combobox with encodings to choose can be + * properly initialized. + * + * @return the current Encoding of the Terminal. + * @since org.eclipse.tm.terminal 2.0 + */ + String getEncoding(); + + /** + * Show a text in the terminal. If puts newlines at the beginning and the + * end. + * + * @param text TODO: Michael Scharf: Is this really needed? + */ + void displayTextInTerminal(String text); + + /** + * @return a stream used to write to the terminal. Any bytes written to this + * stream appear in the terminal or are interpreted by the emulator as + * control sequences. The stream in the opposite direction, terminal + * to remote is in {@link ITerminalConnector#getTerminalToRemoteStream()}. + */ + OutputStream getRemoteToTerminalOutputStream(); + + /** + * 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 mechanism! + */ + void setMsg(String msg); + + /** + * Sets if or if not the terminal view control should try to reconnect + * the terminal connection if the user hits ENTER in a closed terminal. + *

            + * Reconnect on ENTER if terminal is closed is enabled by default. + * + * @param on True to enable the reconnect, false to disable it. + */ + void setConnectOnEnterIfClosed(boolean on); + + /** + * Returns if or if not the terminal view control should try to reconnect + * the terminal connection if the user hits ENTER in a closed terminal. + * + * @return True the reconnect is enabled, false if disabled. + */ + boolean isConnectOnEnterIfClosed(); + + /** + * Enables VT100 line wrapping mode (default is off). + * This corresponds to the VT100 'eat_newline_glitch' terminal capability. + * If enabled, writing to the rightmost column does not cause + * an immediate wrap to the next line. Instead the line wrap occurs on the + * next output character. + * + * @param enable whether to enable or disable VT100 line wrapping mode + */ + void setVT100LineWrapping(boolean enable); + + /** + * @return whether VT100 line wrapping mode is enabled + */ + boolean isVT100LineWrapping(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/Logger.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/Logger.java new file mode 100644 index 00000000000..25f3c6649ac --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/Logger.java @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (c) 2005, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Fran Litterio (Wind River) - initial API and implementation + * Ted Williams (Wind River) - refactored into org.eclipse namespace + * Michael Scharf (Wind River) - split into core, view and connector plugins + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +import java.io.FileOutputStream; +import java.io.PrintStream; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.tm.internal.terminal.control.impl.TerminalPlugin; + +/** + * 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);
            + * 
            + * + * @author Fran Litterio + *

            + * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the Target Management team. + *

            + */ +public final class Logger { + public static final String TRACE_DEBUG_LOG = "org.eclipse.tm.terminal.control/debug/log"; //$NON-NLS-1$ + public static final String TRACE_DEBUG_LOG_CHAR = "org.eclipse.tm.terminal.control/debug/log/char"; //$NON-NLS-1$ + public static final String TRACE_DEBUG_LOG_VT100BACKEND = "org.eclipse.tm.terminal.control/debug/log/VT100Backend"; //$NON-NLS-1$ + + private static PrintStream logStream; + + static { + // Any of the three known debugging options turns on the creation of the log file + boolean createLogFile = TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG) + || TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG_CHAR) + || TerminalPlugin.isOptionEnabled(TRACE_DEBUG_LOG_VT100BACKEND); + + // Log only if tracing is enabled + if (createLogFile && TerminalPlugin.getDefault() != null) { + IPath logFile = Platform.getStateLocation(TerminalPlugin.getDefault().getBundle()); + if (logFile != null && logFile.toFile().isDirectory()) { + logFile = logFile.append("tmterminal.log"); //$NON-NLS-1$ + try { + logStream = new PrintStream(new FileOutputStream(logFile.toFile(), true)); + } catch (Exception ex) { + logStream = System.err; + logStream.println("Exception when opening log file -- logging to stderr!"); //$NON-NLS-1$ + ex.printStackTrace(logStream); + } + } + } + } + + /** + * Encodes a String such that non-printable control characters are + * converted into user-readable escape sequences for logging. + * @param message String to encode + * @return encoded String + */ + public static final String encode(String message) { + boolean encoded = false; + StringBuffer buf = new StringBuffer(message.length()+32); + for (int i=0; i=' ' && c<'\u007f') { + buf.append(c); + } else if (c <= '\u00ff') { + buf.append('\\'); buf.append('x'); + buf.append(Integer.toHexString(c)); + encoded=true; + } else { + buf.append('\\'); buf.append('u'); + if (c<='\u0fff') { + buf.append('0'); + } + buf.append(Integer.toHexString(c)); + encoded=true; + } + } + } + if (encoded) { + return buf.toString(); + } + return message; + } + + /** + * Checks if logging is enabled. + * @return true if logging is enabled. + */ + public static final boolean isLogEnabled() { + return (logStream!=null); + } + + /** + * 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. + + 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(); + } + } + + /** + * Writes a stack trace for an exception to both Standard Error and to the + * log file. + */ + public static final void logException(Exception ex) { + // log in eclipse error log + if (TerminalPlugin.getDefault() != null) { + TerminalPlugin.getDefault().getLog().log(new Status(IStatus.ERROR, TerminalPlugin.PLUGIN_ID, IStatus.OK, ex.getMessage(), ex)); + } else { + ex.printStackTrace(); + } + // Additional Tracing for debug purposes: + // Read my own stack to get the class name, method name, and line number + // of where this method was called + if(logStream!=null) { + 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; + + 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); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/NullSettingsStore.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/NullSettingsStore.java new file mode 100644 index 00000000000..16e6432f826 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/NullSettingsStore.java @@ -0,0 +1,41 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +/** + * A settings store implementation doing nothing. + */ +public class NullSettingsStore implements ISettingsStore { + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String) + */ + @Override + public String get(String key) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String, java.lang.String) + */ + @Override + public String get(String key, String defaultValue) { + return defaultValue; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#put(java.lang.String, java.lang.String) + */ + @Override + public void put(String key, String value) { + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/TerminalConnectorExtension.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/TerminalConnectorExtension.java new file mode 100644 index 00000000000..6eea871b388 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/TerminalConnectorExtension.java @@ -0,0 +1,100 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.RegistryFactory; +import org.eclipse.tm.internal.terminal.connector.TerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +/** + * A factory to get {@link ITerminalConnector} instances. + * + * @author Michael Scharf + * + * @noextend This class is not intended to be subclassed by clients. + * @noinstantiate This class is not intended to be instantiated by clients. + * + *

            + * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will work or + * that it will remain the same. Please do not use this API without consulting + * with the Target Management + * team. + *

            + */ +public class TerminalConnectorExtension { + static private ITerminalConnector makeConnector(final IConfigurationElement config) { + String id = config.getAttribute("id"); //$NON-NLS-1$ + if(id==null || id.length()==0) + id=config.getAttribute("class"); //$NON-NLS-1$ + String name= config.getAttribute("name"); //$NON-NLS-1$ + if(name==null || name.length()==0) { + name=id; + } + String hidden = config.getAttribute("hidden"); //$NON-NLS-1$ + boolean isHidden = hidden != null ? new Boolean(hidden).booleanValue() : false; + TerminalConnector.Factory factory=new TerminalConnector.Factory(){ + public TerminalConnectorImpl makeConnector() throws Exception { + return (TerminalConnectorImpl)config.createExecutableExtension("class"); //$NON-NLS-1$ + }}; + return new TerminalConnector(factory,id,name, isHidden); + } + + /** + * Return a specific terminal connector for a given connector id. The + * terminal connector is not yet instantiated to any real connection. + * + * @param id the id of the terminal connector in the + * org.eclipse.tm.terminal.control.connectors + * extension point + * @return a new ITerminalConnector with id or null if there + * is no extension with that id. + * @since org.eclipse.tm.terminal 2.0 + */ + public static ITerminalConnector makeTerminalConnector(String id) { + IConfigurationElement[] config = RegistryFactory.getRegistry().getConfigurationElementsFor("org.eclipse.tm.terminal.control.connectors"); //$NON-NLS-1$ + for (int i = 0; i < config.length; i++) { + if(id.equals(config[i].getAttribute("id"))) { //$NON-NLS-1$ + return makeConnector(config[i]); + } + } + return null; + } + /** + * Return a list of available terminal connectors (connection types). + * + * The terminal connectors returned are not yet instantiated to any real + * connection. Each terminal connector can connect to one remote system at a + * time. + * + * @return a new list of {@link ITerminalConnector} instances defined in the + * org.eclipse.tm.terminal.control.connectors + * extension point + * @since org.eclipse.tm.terminal 2.0 return value is ITerminalConnector[] + */ + public static ITerminalConnector[] makeTerminalConnectors() { + IConfigurationElement[] config = RegistryFactory.getRegistry().getConfigurationElementsFor("org.eclipse.tm.terminal.control.connectors"); //$NON-NLS-1$ + List result=new ArrayList(); + for (int i = 0; i < config.length; i++) { + result.add(makeConnector(config[i])); + } + return result.toArray(new ITerminalConnector[result.size()]); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/TerminalState.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/TerminalState.java new file mode 100644 index 00000000000..9425cbf7eaf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/TerminalState.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2006, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - fixed copyright headers and beautified + * Michael Scharf (Wind River) - [262996] get rid of TerminalState.OPENED + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api; + +/** + * Represent the sate of a terminal connection. + * In java 1.5 this would be an enum. + * @author Michael Scharf + * + *

            + * EXPERIMENTAL. This class or interface has been added as + * part of a work in progress. There is no guarantee that this API will + * work or that it will remain the same. Please do not use this API without + * consulting with the Target Management team. + *

            + */ +public class TerminalState { + /** + * The terminal is not connected. + */ + public final static TerminalState CLOSED=new TerminalState("CLOSED"); //$NON-NLS-1$ + + /** + * The terminal is about to connect. + */ + public final static TerminalState CONNECTING=new TerminalState("CONNECTING..."); //$NON-NLS-1$ + + /** + * The terminal is connected. + */ + public final static TerminalState CONNECTED=new TerminalState("CONNECTED"); //$NON-NLS-1$ + + private final String fState; + + public TerminalState(String state) { + fState = state; + } + + public String toString() { + return fState; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/provider/TerminalConnectorImpl.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/provider/TerminalConnectorImpl.java new file mode 100644 index 00000000000..7b22cc3cdb7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/provisional/api/provider/TerminalConnectorImpl.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.provisional.api.provider; + +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +/** + * Abstract base class for all terminal connector implementations to be + * registered via the org.eclipse.tm.terminal.control.connectors + * extension point. + * + * @since org.eclipse.tm.terminal 2.0 + */ +public abstract class TerminalConnectorImpl { + + /** + * The TerminalControl associated with this connector. + * Required for advertising state changes when needed. + */ + protected ITerminalControl fControl; + + /** + * Initialize this connector. This is called once after the constructor, in + * order to perform any required initializations such as loading required + * native libraries. Any work that may lead to runtime exceptions should be + * done in this method rather than in the constructor. + * + * @throws Exception when the connector fails to initialize (due to missing + * required libraries, for instance). + */ + public void initialize() throws Exception { + } + + /** + * Connect using the current state of the settings. + * + * This method is designed to be overridden by actual implementations, in + * order to open the streams required for communicating with the remote + * side. Extenders must call super.connect(control) as the + * first thing they are doing. + * + * @param control Used to inform the UI about state changes and messages + * from the connection. + */ + public void connect(ITerminalControl control) { + Logger.log("entered."); //$NON-NLS-1$ + fControl = control; + } + + /** + * Disconnect if connected. Else do nothing. Has to set the state of the + * {@link ITerminalControl} when finished disconnecting. + */ + public final void disconnect() { + Logger.log("entered."); //$NON-NLS-1$ + doDisconnect(); + fControl.setState(TerminalState.CLOSED); + } + + /** + * Disconnect if connected. Else do nothing. Clients should override to + * perform any extra work needed for disconnecting. + */ + protected void doDisconnect() { + // Do nothing by default + } + + /** + * @return the terminal to remote stream (bytes written to this stream will + * be sent to the remote site). For the stream in the other direction (remote to + * terminal see {@link ITerminalControl#getRemoteToTerminalOutputStream()} + */ + abstract public OutputStream getTerminalToRemoteStream(); + + /** + * @return A string that represents the settings of the connection. This representation + * may be shown in the status line of the terminal view. + */ + abstract public String getSettingsSummary(); + + /** + * Test if local echo is needed. The default implementation returns + * false. Override to modify this behavior. + * + * @return true if a local echo is needed. TODO:Michael Scharf: this should + * be handed within the connection.... + */ + public boolean isLocalEcho() { + return false; + } + + /** + * Set or reset the settings store to the default values. + */ + public void setDefaultSettings() { + // do nothing by default + } + + /** + * Load the state or settings of this connection. Is typically called before + * {@link #connect(ITerminalControl)}. + * + * Connectors that have nothing to configure do not need to implement this. + * Those terminals that do have configuration need to override this method + * to load settings. + * + * @param store a string based data store. Short keys like "foo" can be used + * to store the state of the connection. + */ + public void load(ISettingsStore store) { + // do nothing by default + } + + /** + * When the view or dialog containing the terminal is closed, the state of + * the connection is saved into the settings store store. + * + * Connectors that have no state or settings to persist do not need to + * override this. Others should override to persist their settings. + * + * @param store the store for persisting settings. + */ + public void save(ISettingsStore store) { + // do nothing by default + } + + /** + * Notify the remote site that the size of the terminal has changed. + * + * Concrete connectors should override this if they have the possibility to + * inform the remote about changed terminal size. + * + * @param newWidth the new width in characters. + * @param newHeight the new height in characters. + */ + public void setTerminalSize(int newWidth, int newHeight) { + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/AbstractTextCanvasModel.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/AbstractTextCanvasModel.java new file mode 100644 index 00000000000..c6035b38eb4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/AbstractTextCanvasModel.java @@ -0,0 +1,382 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [168197] Fix Terminal for CDC-1.1/Foundation-1.1 + * Anton Leherbauer (Wind River) - [219589] Copy an entire line selection + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; + +abstract public class AbstractTextCanvasModel implements ITextCanvasModel { + protected List fListeners = new ArrayList(); + private int fCursorLine; + private int fCursorColumn; + private boolean fShowCursor; + private long fCursorTime; + private boolean fCursorIsEnabled; + private final ITerminalTextDataSnapshot fSnapshot; + private int fLines; + + private int fSelectionStartLine=-1; + private int fSeletionEndLine; + private int fSelectionStartCoumn; + private int fSelectionEndColumn; + private ITerminalTextDataSnapshot fSelectionSnapshot; + private String fCurrentSelection=""; //$NON-NLS-1$ + private final Point fSelectionAnchor=new Point(0,0); + /** + * do not update while update is running + */ + boolean fInUpdate; + private int fCols; + + public AbstractTextCanvasModel(ITerminalTextDataSnapshot snapshot) { + fSnapshot=snapshot; + fLines=fSnapshot.getHeight(); + } + public void addCellCanvasModelListener(ITextCanvasModelListener listener) { + fListeners.add(listener); + } + + public void removeCellCanvasModelListener(ITextCanvasModelListener listener) { + fListeners.remove(listener); + } + + protected void fireCellRangeChanged(int x, int y, int width, int height) { + for (Iterator iter = fListeners.iterator(); iter.hasNext();) { + ITextCanvasModelListener listener = iter.next(); + listener.rangeChanged(x, y, width, height); + } + } + protected void fireDimensionsChanged( int width,int height) { + for (Iterator iter = fListeners.iterator(); iter.hasNext();) { + ITextCanvasModelListener listener = iter.next(); + listener.dimensionsChanged(width,height); + } + + } + protected void fireTerminalDataChanged() { + for (Iterator iter = fListeners.iterator(); iter.hasNext();) { + ITextCanvasModelListener listener = iter.next(); + listener.terminalDataChanged(); + } + + } + + public ITerminalTextDataReadOnly getTerminalText() { + return fSnapshot; + } + protected ITerminalTextDataSnapshot getSnapshot() { + return fSnapshot; + } + protected void updateSnapshot() { + if(!fInUpdate && fSnapshot.isOutOfDate()) { + fInUpdate=true; + try { + fSnapshot.updateSnapshot(false); + if(fSnapshot.hasTerminalChanged()) + fireTerminalDataChanged(); + // TODO why does hasDimensionsChanged not work?????? + // if(fSnapshot.hasDimensionsChanged()) + // fireDimensionsChanged(); + if(fLines!=fSnapshot.getHeight() || fCols!=fSnapshot.getWidth()) { + fireDimensionsChanged(fSnapshot.getWidth(),fSnapshot.getHeight()); + fLines=fSnapshot.getHeight(); + fCols=fSnapshot.getWidth(); + } + int y=fSnapshot.getFirstChangedLine(); + // has any line changed? + if(y=getSnapshot().getHeight()) { + cursorLine=getSnapshot().getHeight()-1; + cursorColumn=getSnapshot().getWidth()-1; + } + // has the cursor moved? + if(fCursorLine!=cursorLine || fCursorColumn!=cursorColumn) { + // hide the old cursor! + fShowCursor=false; + // clean the previous cursor + // bug 206363: paint also the char to the left and right of the cursor - see also below + int col=fCursorColumn; + int width=2; + if(col>0) { + col--; + width++; + } + fireCellRangeChanged(col, fCursorLine, width, 1); + // the cursor is shown when it moves! + fShowCursor=true; + fCursorTime=System.currentTimeMillis(); + fCursorLine=cursorLine; + fCursorColumn=cursorColumn; + // and draw the new cursor + fireCellRangeChanged(fCursorColumn, fCursorLine, 1, 1); + } else { + long t=System.currentTimeMillis(); + // TODO make the cursor blink time customisable + if(t-fCursorTime>500) { + fShowCursor=!fShowCursor; + fCursorTime=t; + // on some windows machines, there is some left + // over when updating the cursor . + // https://bugs.eclipse.org/bugs/show_bug.cgi?id=206363 + int col=fCursorColumn; + int width=2; + if(col>0) { + col--; + width++; + } + fireCellRangeChanged(col, fCursorLine, width, 1); + } + } + } + public void setVisibleRectangle(int startLine, int startCol, int height, int width) { + fSnapshot.setInterestWindow(Math.max(0,startLine), Math.max(1,height)); + update(); + } + protected void showCursor(boolean show) { + fShowCursor=true; + } + public void setCursorEnabled(boolean visible) { + fCursorTime=System.currentTimeMillis(); + fShowCursor=visible; + fCursorIsEnabled=visible; + fireCellRangeChanged(fCursorColumn, fCursorLine, 1, 1); + } + public boolean isCursorEnabled() { + return fCursorIsEnabled; + } + + public Point getSelectionEnd() { + if(fSelectionStartLine<0) + return null; + else + return new Point(fSelectionEndColumn, fSeletionEndLine); + } + + public Point getSelectionStart() { + if (fSelectionStartLine < 0) + return null; + else + return new Point(fSelectionStartCoumn,fSelectionStartLine); + } + public Point getSelectionAnchor() { + if(fSelectionStartLine<0) + return null; + return new Point(fSelectionAnchor.x,fSelectionAnchor.y); + } + public void setSelectionAnchor(Point anchor) { + fSelectionAnchor.x=anchor.x; + fSelectionAnchor.y=anchor.y; + } + + public void setSelection(int startLine, int endLine, int startColumn, int endColumn) { +// System.err.println(startLine+","+endLine+","+startColumn+","+endColumn); + doSetSelection(startLine, endLine, startColumn, endColumn); + fCurrentSelection=extractSelectedText(); + } + private void doSetSelection(int startLine, int endLine, int startColumn, int endColumn) { + assert(startLine<0 || startLine<=endLine); + if(startLine>=0) { + if(fSelectionSnapshot==null) { + fSelectionSnapshot=fSnapshot.getTerminalTextData().makeSnapshot(); + fSelectionSnapshot.updateSnapshot(true); + } + } else if(fSelectionSnapshot!=null) { + fSelectionSnapshot.detach(); + fSelectionSnapshot=null; + } + int oldStart=fSelectionStartLine; + int oldEnd=fSeletionEndLine; + fSelectionStartLine = startLine; + fSeletionEndLine = endLine; + fSelectionStartCoumn = startColumn; + fSelectionEndColumn = endColumn; + if(fSelectionSnapshot!=null) { + fSelectionSnapshot.setInterestWindow(0, fSelectionSnapshot.getHeight()); + } + int changedStart; + int changedEnd; + if(oldStart<0) { + changedStart=fSelectionStartLine; + changedEnd=fSeletionEndLine; + } else if(fSelectionStartLine<0) { + changedStart=oldStart; + changedEnd=oldEnd; + } else { + changedStart=Math.min(oldStart, fSelectionStartLine); + changedEnd=Math.max(oldEnd, fSeletionEndLine); + } + if(changedStart>=0) { + fireCellRangeChanged(0, changedStart, fSnapshot.getWidth(), changedEnd-changedStart+1); + } + } + + public boolean hasLineSelection(int line) { + if (fSelectionStartLine < 0) + return false; + else + return line >= fSelectionStartLine && line <= fSeletionEndLine; + } + + public String getSelectedText() { + return fCurrentSelection; + } + + // helper to sanitize text copied out of a snapshot + private static String scrubLine(String text) { + // get rid of the empty space at the end of the lines + // text=text.replaceAll("\000+$",""); //$NON-NLS-1$//$NON-NLS-2$ + // + int i = text.length() - 1; + while (i >= 0 && text.charAt(i) == '\000') { + i--; + } + text = text.substring(0, i + 1); + // + // null means space + return text.replace('\000', ' '); + } + + /** + * Calculates the currently selected text + * @return the currently selected text + */ + private String extractSelectedText() { + if(fSelectionStartLine<0 || fSelectionStartCoumn<0 || fSelectionSnapshot==null) + return ""; //$NON-NLS-1$ + StringBuffer buffer=new StringBuffer(); + for (int line = fSelectionStartLine; line <= fSeletionEndLine; line++) { + String text; + char[] chars=fSelectionSnapshot.getChars(line); + if(chars!=null) { + text=new String(chars); + if(line==fSeletionEndLine && fSelectionEndColumn >= 0) + text=text.substring(0, Math.min(fSelectionEndColumn+1,text.length())); + if(line==fSelectionStartLine) + text=text.substring(Math.min(fSelectionStartCoumn,text.length())); + text=scrubLine(text); + } else { + text=""; //$NON-NLS-1$ + } + buffer.append(text); + if(line < fSeletionEndLine && !fSelectionSnapshot.isWrappedLine(line)) + buffer.append('\n'); + } + return buffer.toString(); + } + private void updateSelection() { + if (fSelectionSnapshot != null && fSelectionSnapshot.isOutOfDate()) { + fSelectionSnapshot.updateSnapshot(true); + // has the selection moved? + if (fSelectionSnapshot != null && fSelectionStartLine >= 0 && fSelectionSnapshot.getScrollWindowSize() > 0) { + int start = fSelectionStartLine + fSelectionSnapshot.getScrollWindowShift(); + int end = fSeletionEndLine + fSelectionSnapshot.getScrollWindowShift(); + if (start < 0) + if (end >= 0) + start = 0; + else + start = -1; + doSetSelection(start, end, fSelectionStartCoumn, fSelectionEndColumn); + } + // check if the content of the selection has changed. If the content has + // changed, clear the selection + if (fCurrentSelection.length()>0 && fSelectionSnapshot != null + && fSelectionSnapshot.getFirstChangedLine() <= fSeletionEndLine + && fSelectionSnapshot.getLastChangedLine() >= fSelectionStartLine) { + // has the selected text changed? + if (!fCurrentSelection.equals(extractSelectedText())) { + setSelection(-1, -1, -1, -1); + } + } + // update the observed window... + if (fSelectionSnapshot != null) + // todo make -1 to work! + fSelectionSnapshot.setInterestWindow(0, fSelectionSnapshot.getHeight()); + } + } + + @Override + public String getAllText() { + + // Make a snapshot of the whole text data + ITerminalTextDataSnapshot snapshot = fSnapshot.getTerminalTextData().makeSnapshot(); + snapshot.updateSnapshot(true); + snapshot.detach(); + + // Extract the data + StringBuffer sb = new StringBuffer(); + for (int line = 0; line < snapshot.getHeight(); line++) { + char[] chars = snapshot.getChars(line); + String text; + if (chars != null) { + text = scrubLine(new String(chars)); // take care of NULs + } else { + text = ""; //$NON-NLS-1$ null arrays represent empty lines + } + sb.append(text); + // terminate lines except (1) the last one and (2) wrapped lines + if ((line < snapshot.getHeight() - 1) && !snapshot.isWrappedLine(line)) { + sb.append('\n'); + } + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/GridCanvas.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/GridCanvas.java new file mode 100644 index 00000000000..dc5d4c56993 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/GridCanvas.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [294468] Fix scroller and text line rendering + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; + +/** + * A Grid based Canvas. The canvas has rows and columns. + * CellPainting is done with the abstract method drawCell + */ +abstract public class GridCanvas extends VirtualCanvas { + /** width of a cell */ + private int fCellWidth; + /** height of a cell */ + private int fCellHeight; + + public GridCanvas(Composite parent, int style) { + super(parent, style); + addListener(SWT.MouseWheel, new Listener() { + public void handleEvent(Event event) { + if(getVerticalBar().isVisible()) { + int delta=-fCellHeight; + if(event.count<0) + delta=-delta; + scrollYDelta(delta); + } + event.doit=false; + } + }); + + } + + /** template method paint. + * iterates over all cells in the clipping rectangle and paints them. + */ + protected void paint(GC gc) { + Rectangle clipping=gc.getClipping(); + if(clipping.width==0 || clipping.height==0) + return; + Rectangle clientArea= getScreenRectInVirtualSpace(); + // Beginning coordinates + int xOffset=clientArea.x; + int yOffset=clientArea.y; + int colFirst=virtualXToCell(xOffset+clipping.x); + if(colFirst>getCols()) + colFirst=getCols(); + else if (colFirst < 0) { + colFirst = 0; + } + int rowFirst=virtualYToCell(yOffset+clipping.y); + // End coordinates + int colLast=virtualXToCell(xOffset+clipping.x+clipping.width+fCellWidth); + if(colLast>getCols()) + colLast=getCols(); + int rowLast=virtualYToCell(yOffset+clipping.y+clipping.height+fCellHeight); + if(rowLast>getRows()) + rowLast=getRows(); + // System.out.println(rowFirst+"->"+rowLast+" "+System.currentTimeMillis()); + // draw the cells + for(int row=rowFirst;row<=rowLast;row++) { + int cx=colFirst*fCellWidth-xOffset; + int cy=row*fCellHeight-yOffset; + drawLine(gc,row,cx,cy,colFirst,colLast); + } + paintUnoccupiedSpace(gc,clipping); + } + /** + * @param gc + * @param row the line to draw + * @param x coordinate on screen + * @param y coordinate on screen + * @param colFirst first column to draw + * @param colLast last column to draw + */ + abstract void drawLine(GC gc, int row, int x, int y, int colFirst, int colLast); + + abstract protected int getRows(); + abstract protected int getCols(); + + protected void setCellWidth(int cellWidth) { + fCellWidth = cellWidth; + getHorizontalBar().setIncrement(fCellWidth); + } + + public int getCellWidth() { + return fCellWidth; + } + + protected void setCellHeight(int cellHeight) { + fCellHeight = cellHeight; + getVerticalBar().setIncrement(fCellHeight); + } + + public int getCellHeight() { + return fCellHeight; + } + + int virtualXToCell(int x) { + return x/fCellWidth; + } + + int virtualYToCell(int y) { + return y/fCellHeight; + } + + protected Point screenPointToCell(int x, int y) { + x=screenXtoVirtual(x)/fCellWidth; + y=screenYtoVirtual(y)/fCellHeight; + return new Point(x,y); + } + + Point screenPointToCell(Point point) { + return screenPointToCell(point.x,point.y); + } + + protected Point cellToOriginOnScreen(int x, int y) { + x=virtualXtoScreen(fCellWidth*x); + y=virtualYtoScreen(fCellHeight*y); + return new Point(x,y); + } + + Point cellToOriginOnScreen(Point cell) { + return cellToOriginOnScreen(cell.x,cell.y); + } + + Rectangle getCellScreenRect(Point cell) { + return getCellScreenRect(cell.x,cell.y); + } + + Rectangle getCellScreenRect(int x, int y) { + x=fCellWidth*virtualXtoScreen(x); + y=fCellHeight*virtualYtoScreen(y); + return new Rectangle(x,y,fCellWidth,fCellHeight); + } + + protected Rectangle getCellVirtualRect(Point cell) { + return getCellVirtualRect(cell.x,cell.y); + } + + Rectangle getCellVirtualRect(int x, int y) { + x=fCellWidth*x; + y=fCellHeight*y; + return new Rectangle(x,y,fCellWidth,fCellHeight); + } + protected void viewRectangleChanged(int x, int y, int width, int height) { + int cellX=virtualXToCell(x); + int cellY=virtualYToCell(y); + // End coordinates + int xE=virtualXToCell(x+width); +// if(xE>getCols()) +// xE=getCols(); + int yE=virtualYToCell(y+height); +// if(yE>getRows()) +// yE=getRows(); + visibleCellRectangleChanged(cellX,cellY,xE-cellX,yE-cellY); + } + + /** + * Called when the viewed part has changed. + * Override when you need this information.... + * Is only called if the values change (well, almost) + * @param x origin of visible cells + * @param y origin of visible cells + * @param width number of cells visible in x direction + * @param height number of cells visible in y direction + */ + protected void visibleCellRectangleChanged(int x, int y, int width, int height) { + } + + protected void setVirtualExtend(int width, int height) { + int cellHeight = getCellHeight(); + if (cellHeight > 0) { + height -= height % cellHeight; + } + super.setVirtualExtend(width, height); + } + + protected void setVirtualOrigin(int x, int y) { + int cellHeight = getCellHeight(); + if (cellHeight > 0) { + int remainder = y % cellHeight; + if (remainder < 0) { + y -= (cellHeight + remainder); + } else { + y -= remainder; + } + } + super.setVirtualOrigin(x, y); + } + + protected void scrollY(ScrollBar vBar) { + int vSelection = vBar.getSelection (); + Rectangle bounds = getVirtualBounds(); + int y = -vSelection; + int cellHeight = getCellHeight(); + if (cellHeight > 0) { + int remainder = y % cellHeight; + if (remainder < 0) { + y -= (cellHeight + remainder); + } else { + y -= remainder; + } + } + int deltaY = y - bounds.y; + if(deltaY!=0) { + scrollSmart(0,deltaY); + setVirtualOrigin(bounds.x, bounds.y += deltaY); + } + if (-bounds.y + getRows() * getCellHeight() >= bounds.height) { + // scrolled to bottom - need to redraw bottom area + Rectangle clientRect = getClientArea(); + redraw(0, clientRect.height - fCellHeight, clientRect.width, fCellHeight, false); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ILinelRenderer.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ILinelRenderer.java new file mode 100644 index 00000000000..9666fd9a910 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ILinelRenderer.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [294468] Fix scroller and text line rendering + * Martin Oberhuber (Wind River) - [265352][api] Allow setting fonts programmatically + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; + +/** + * + */ +public interface ILinelRenderer { + int getCellWidth(); + int getCellHeight(); + void drawLine(ITextCanvasModel model, GC gc, int line, int x, int y, int colFirst, int colLast); + /** + * Update for a font change from the global JFace Registry. + */ + void onFontChange(); + /** + * Set a new font + * @param fontName Jface name of the new font + * @since 3.2 + */ + void updateFont(String fontName); + void setInvertedColors(boolean invert); + Color getDefaultBackgroundColor(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ITextCanvasModel.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ITextCanvasModel.java new file mode 100644 index 00000000000..0fbba76959c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ITextCanvasModel.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +import org.eclipse.swt.graphics.Point; +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; + +public interface ITextCanvasModel { + void addCellCanvasModelListener(ITextCanvasModelListener listener); + void removeCellCanvasModelListener(ITextCanvasModelListener listener); + + ITerminalTextDataReadOnly getTerminalText(); + /** + * This is is + * @param startLine + * @param startCol + * @param height + * @param width + */ + void setVisibleRectangle(int startLine, int startCol, int height, int width); + + /** + * @return true when the cursor is shown (used for blinking cursors) + */ + boolean isCursorOn(); + /** + * Show/Hide the cursor. + * @param visible + */ + void setCursorEnabled(boolean visible); + + /** + * @return true if the cursor is shown. + */ + boolean isCursorEnabled(); + + /** + * @return the line of the cursor + */ + int getCursorLine(); + /** + * @return the column of the cursor + */ + int getCursorColumn(); + + /** + * @return the start of the selection or null if nothing is selected + * {@link Point#x} is the column and {@link Point#y} is the line. + */ + Point getSelectionStart(); + /** + * @return the end of the selection or null if nothing is selected + * {@link Point#x} is the column and {@link Point#y} is the line. + */ + Point getSelectionEnd(); + + Point getSelectionAnchor(); + + void setSelectionAnchor(Point anchor); + /** + * Sets the selection. A negative startLine clears the selection. + * @param startLine + * @param endLine + * @param startColumn + * @param endColumn + */ + void setSelection(int startLine, int endLine, int startColumn, int endColumn); + + /** + * @param line + * @return true if line is part of the selection + */ + boolean hasLineSelection(int line); + + String getSelectedText(); + + /** + * Collect and return all text present in the model. + * + *

            Individual lines of the returned text are separated by '\n'. + * + *

            The method is primarily designed for test automation. + * + * @since 4.4 + */ + String getAllText(); +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ITextCanvasModelListener.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ITextCanvasModelListener.java new file mode 100644 index 00000000000..bc942890baa --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/ITextCanvasModelListener.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +/** + */ +public interface ITextCanvasModelListener { + void rangeChanged(int col, int line, int width, int height); + void dimensionsChanged(int cols, int rows); + /** + * Called when any text change happened. Used to scroll to the + * end of text in auto scroll mode. This does not get fired + * when the window of interest has changed! + */ + void terminalDataChanged(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/PipedInputStream.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/PipedInputStream.java new file mode 100644 index 00000000000..4c00d995454 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/PipedInputStream.java @@ -0,0 +1,312 @@ +/******************************************************************************* + * Copyright (c) 1996, 2011 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Douglas Lea (Addison Wesley) - [cq:1552] BoundedBufferWithStateTracking adapted to BoundedByteBuffer + * Martin Oberhuber (Wind River) - the waitForAvailable method + * Martin Oberhuber (Wind River) - [208166] Avoid unnecessary arraycopy in BoundedByteBuffer + * Pawel Piech (Wind River) - [333613] "Job found still running" after shutdown + *******************************************************************************/ + +package org.eclipse.tm.internal.terminal.textcanvas; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + +/** + * The main purpose of this class is to start a runnable in the + * display thread when data is available and to pretend no data + * is available after a given amount of time the runnable is running. + * + */ +public class PipedInputStream extends InputStream { + /** + * The output stream used by the terminal backend to write to the terminal + */ + protected final OutputStream fOutputStream; + /** + * A blocking byte queue. + */ + private final BoundedByteBuffer fQueue; + + /** + * A byte bounded buffer used to synchronize the input and the output stream. + *

            + * Adapted from BoundedBufferWithStateTracking + * http://gee.cs.oswego.edu/dl/cpj/allcode.java + * http://gee.cs.oswego.edu/dl/cpj/ + *

            + * BoundedBufferWithStateTracking is part of the examples for the book + * Concurrent Programming in Java: Design Principles and Patterns by + * Doug Lea (ISBN 0-201-31009-0). Second edition published by + * Addison-Wesley, November 1999. The code is + * Copyright(c) Douglas Lea 1996, 1999 and released to the public domain + * and may be used for any purposes whatsoever. + *

            + * For some reasons a solution based on + * PipedOutputStream/PipedIntputStream + * does work *very* slowly: + * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4404700 + *

            + * + */ + private class BoundedByteBuffer { + protected final byte[] fBuffer; // the elements + protected int fPutPos = 0; // circular indices + protected int fTakePos = 0; + protected int fUsedSlots = 0; // the count + private boolean fClosed; + public BoundedByteBuffer(int capacity) throws IllegalArgumentException { + // make sure we don't deadlock on too small capacity + if (capacity <= 0) + throw new IllegalArgumentException(); + fBuffer = new byte[capacity]; + } + /** + * @return the bytes available for {@link #read()} + * Must be called with a lock on this! + */ + public int available() { + return fUsedSlots; + } + /** + * Writes a single byte to the buffer. Blocks if the buffer is full. + * @param b byte to write to the buffer + * @throws InterruptedException when the thread is interrupted while waiting + * for the buffer to become ready + * Must be called with a lock on this! + */ + public void write(byte b) throws InterruptedException { + while (fUsedSlots == fBuffer.length) + // wait until not full + wait(); + + fBuffer[fPutPos] = b; + fPutPos = (fPutPos + 1) % fBuffer.length; // cyclically increment + + if (fUsedSlots++ == 0) // signal if was empty + notifyAll(); + } + public int getFreeSlots() { + return fBuffer.length - fUsedSlots; + } + public void write(byte[] b, int off, int len) throws InterruptedException { + assert len<=getFreeSlots(); + while (fUsedSlots == fBuffer.length) + // wait until not full + wait(); + int n = Math.min(len, fBuffer.length - fPutPos); + System.arraycopy(b, off, fBuffer, fPutPos, n); + if (fPutPos + len > fBuffer.length) + System.arraycopy(b, off + n, fBuffer, 0, len - n); + fPutPos = (fPutPos + len) % fBuffer.length; // cyclically increment + boolean wasEmpty = fUsedSlots == 0; + fUsedSlots += len; + if (wasEmpty) // signal if was empty + notifyAll(); + } + /** + * Read a single byte. Blocks until a byte is available. + * @return a byte from the buffer + * @throws InterruptedException when the thread is interrupted while waiting + * for the buffer to become ready + * Must be called with a lock on this! + */ + public int read() throws InterruptedException { + while (fUsedSlots == 0) { + if(fClosed) + return -1; + // wait until not empty + wait(); + } + byte b = fBuffer[fTakePos]; + fTakePos = (fTakePos + 1) % fBuffer.length; + + if (fUsedSlots-- == fBuffer.length) // signal if was full + notifyAll(); + return b; + } + public int read(byte[] cbuf, int off, int len) throws InterruptedException { + assert len<=available(); + while (fUsedSlots == 0) { + if(fClosed) + return 0; + // wait until not empty + wait(); + } + int n = Math.min(len, fBuffer.length - fTakePos); + System.arraycopy(fBuffer, fTakePos, cbuf, off, n); + if (fTakePos + len > n) + System.arraycopy(fBuffer, 0, cbuf, off + n, len - n); + fTakePos = (fTakePos + len) % fBuffer.length; + boolean wasFull = fUsedSlots == fBuffer.length; + fUsedSlots -= len; + if(wasFull) + notifyAll(); + + return len; + } + public void close() { + fClosed=true; + notifyAll(); + } + public boolean isClosed() { + return fClosed; + } + } + + /** + * An output stream that calls {@link PipedInputStream#textAvailable} + * every time data is written to the stream. The data is written to + * {@link PipedInputStream#fQueue}. + * + */ + class PipedOutputStream extends OutputStream { + public void write(byte[] b, int off, int len) throws IOException { + try { + synchronized (fQueue) { + if(fQueue.isClosed()) + throw new IOException("Stream is closed!"); //$NON-NLS-1$ + int written=0; + while(writtenPipedInputStream is the same as closing the output stream. + * The stream will allow reading data that's still in the pipe after which it will + * throw an IOException. + */ + public void close() throws IOException { + synchronized(fQueue) { + fQueue.close(); + } + } + + public int read(byte[] cbuf, int off, int len) throws IOException { + int n=0; + if(len==0) + return 0; + // read as much as we can using a single synchronized statement + try { + synchronized (fQueue) { + // if nothing available, block and read one byte + if (fQueue.available() == 0) { + // block now until at least one byte is available + int c = fQueue.read(); + // are we at the end of stream + if (c == -1) + return -1; + cbuf[off] = (byte) c; + n++; + } + // is there more data available? + if (n < len && fQueue.available() > 0) { + // read at most available() + int nn = Math.min(fQueue.available(), len - n); + // are we at the end of the stream? + if (nn == 0 && fQueue.isClosed()) { + // if no byte was read, return -1 to indicate end of stream + // else return the bytes we read up to now + if (n == 0) + n = -1; + return n; + } + fQueue.read(cbuf, off + n, nn); + n += nn; + } + + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return n; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/PollingTextCanvasModel.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/PollingTextCanvasModel.java new file mode 100644 index 00000000000..4d0a6581cc3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/PollingTextCanvasModel.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [420928] Terminal widget leaks memory + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; + +/** + * @author Michael.Scharf@scharf-software.com + * + */ +public class PollingTextCanvasModel extends AbstractTextCanvasModel { + private static final int DEFAULT_POLL_INTERVAL = 50; + int fPollInterval = -1; + + /** + * + */ + public PollingTextCanvasModel(ITerminalTextDataSnapshot snapshot) { + super(snapshot); + startPolling(); + } + public void setUpdateInterval(int t) { + fPollInterval = t; + } + public void stopPolling() { + // timerExec only dispatches if the delay is >=0 + fPollInterval = -1; + } + public void startPolling() { + if (fPollInterval < 0) { + fPollInterval = DEFAULT_POLL_INTERVAL; + Display.getDefault().timerExec(fPollInterval, new Runnable(){ + public void run() { + update(); + Display.getDefault().timerExec(fPollInterval, this); + } + }); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/StyleMap.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/StyleMap.java new file mode 100644 index 00000000000..5d4e91a7a0f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/StyleMap.java @@ -0,0 +1,298 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Michael Scharf (Wind River) - [205260] Terminal does not take the font from the preferences + * Michael Scharf (Wind River) - [209746] There are cases where some colors not displayed correctly + * Michael Scharf (Wind River) - [206328] Terminal does not draw correctly with proportional fonts + * Martin Oberhuber (Wind River) - [247700] Terminal uses ugly fonts in JEE package + * Martin Oberhuber (Wind River) - [335358] Fix Terminal color definition + * Martin Oberhuber (Wind River) - [265352][api] Allow setting fonts programmatically + * Martin Oberhuber (Wind River) - [475422] Fix display on MacOSX Retina + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.RGB; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.preferences.ITerminalConstants; +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +public class StyleMap { + private static final String BLACK = "black"; //$NON-NLS-1$ + private static final String WHITE = "white"; //$NON-NLS-1$ + private static final String WHITE_FOREGROUND = "white_foreground"; //$NON-NLS-1$ + private static final String GRAY = "gray"; //$NON-NLS-1$ + private static final String MAGENTA = "magenta"; //$NON-NLS-1$ + private static final String CYAN = "cyan"; //$NON-NLS-1$ + private static final String YELLOW = "yellow"; //$NON-NLS-1$ + private static final String BLUE = "blue"; //$NON-NLS-1$ + private static final String GREEN = "green"; //$NON-NLS-1$ + private static final String RED = "red"; //$NON-NLS-1$ + + private static final String PREFIX = "org.eclipse.tm.internal."; //$NON-NLS-1$ + String fFontName=ITerminalConstants.FONT_DEFINITION; + Map fColorMapForeground=new HashMap(); + Map fColorMapBackground=new HashMap(); + Map fColorMapIntense=new HashMap(); + private Point fCharSize; + private final Style fDefaultStyle; + private boolean fInvertColors; + private boolean fProportional; + private final int[] fOffsets=new int[256]; + StyleMap() { + initColors(); + fDefaultStyle=Style.getStyle(StyleColor.getStyleColor(BLACK),StyleColor.getStyleColor(WHITE)); + updateFont(); + } + private void initColors() { + initForegroundColors(); + initBackgroundColors(); + initIntenseColors(); + } + private void initForegroundColors() { + if(fInvertColors) { + setColor(fColorMapForeground, WHITE, 0, 0, 0); + setColor(fColorMapForeground, WHITE_FOREGROUND, 50, 50, 50); + setColor(fColorMapForeground, BLACK, 229, 229, 229); + } else { + setColor(fColorMapForeground, WHITE, 255, 255, 255); + setColor(fColorMapForeground, WHITE_FOREGROUND, 229, 229, 229); + setColor(fColorMapForeground, BLACK, 50, 50, 50); + } + setColor(fColorMapForeground, RED, 205, 0, 0); + setColor(fColorMapForeground, GREEN, 0, 205, 0); + setColor(fColorMapForeground, BLUE, 0, 0, 238); + setColor(fColorMapForeground, YELLOW, 205, 205, 0); + setColor(fColorMapForeground, CYAN, 0, 205, 205); + setColor(fColorMapForeground, MAGENTA, 205, 0, 205); + setColor(fColorMapForeground, GRAY, 229, 229, 229); + } + + private void initBackgroundColors() { + if(fInvertColors) { + setColor(fColorMapBackground, WHITE, 0, 0, 0); + setColor(fColorMapBackground, WHITE_FOREGROUND, 50, 50, 50); // only used when colors are inverse + setColor(fColorMapBackground, BLACK, 255, 255, 255); + } else { + setColor(fColorMapBackground, WHITE, 255, 255, 255); + setColor(fColorMapBackground, WHITE_FOREGROUND, 229, 229, 229); + setColor(fColorMapBackground, BLACK, 0, 0, 0); + } + setColor(fColorMapBackground, RED, 205, 0, 0); + setColor(fColorMapBackground, GREEN, 0, 205, 0); + setColor(fColorMapBackground, BLUE, 0, 0, 238); + setColor(fColorMapBackground, YELLOW, 205, 205, 0); + setColor(fColorMapBackground, CYAN, 0, 205, 205); + setColor(fColorMapBackground, MAGENTA, 205, 0, 205); + setColor(fColorMapBackground, GRAY, 229, 229, 229); + } + + private void initIntenseColors() { + if(fInvertColors) { + setColor(fColorMapIntense, WHITE, 127, 127, 127); + setColor(fColorMapIntense, WHITE_FOREGROUND, 0, 0, 0); // only used when colors are inverse + setColor(fColorMapIntense, BLACK, 255, 255, 255); + } else { + setColor(fColorMapIntense, WHITE, 255, 255, 255); + setColor(fColorMapIntense, WHITE_FOREGROUND, 255, 255, 255); + setColor(fColorMapIntense, BLACK, 0, 0, 0); + } + setColor(fColorMapIntense, RED, 255, 0, 0); + setColor(fColorMapIntense, GREEN, 0, 255, 0); + setColor(fColorMapIntense, BLUE, 92, 92, 255); + setColor(fColorMapIntense, YELLOW, 255, 255, 0); + setColor(fColorMapIntense, CYAN, 0, 255, 255); + setColor(fColorMapIntense, MAGENTA, 255, 0, 255); + setColor(fColorMapIntense, GRAY, 255, 255, 255); + } + + private void setColor(Map colorMap, String name, int r, int g, int b) { + String colorName=PREFIX+r+"-"+g+"-"+b; //$NON-NLS-1$//$NON-NLS-2$ + Color color=JFaceResources.getColorRegistry().get(colorName); + if(color==null) { + JFaceResources.getColorRegistry().put(colorName, new RGB(r,g,b)); + color=JFaceResources.getColorRegistry().get(colorName); + } + colorMap.put(StyleColor.getStyleColor(name), color); + colorMap.put(StyleColor.getStyleColor(name.toUpperCase()), color); + } + + public Color getForegrondColor(Style style) { + style = defaultIfNull(style); + Map map = style.isBold() ? fColorMapIntense : fColorMapForeground; + //Map map = fColorMapForeground; + if(style.isReverse()) + return getColor(map ,style.getBackground()); + else + return getColor(map ,style.getForground()); + } + public Color getBackgroundColor(Style style) { + style = defaultIfNull(style); + if(style.isReverse()) + return getColor(fColorMapBackground,style.getForground()); + else + return getColor(fColorMapBackground,style.getBackground()); + } + Color getColor(Map map,StyleColor color) { + Color c=map.get(color); + if(c==null) { + c=Display.getCurrent().getSystemColor(SWT.COLOR_GRAY); + } + return c; + } + private Style defaultIfNull(Style style) { + if(style==null) + style=fDefaultStyle; + return style; + } + public void setInvertedColors(boolean invert) { + if(invert==fInvertColors) + return; + fInvertColors=invert; + initColors(); + } +// static Font getBoldFont(Font font) { +// FontData fontDatas[] = font.getFontData(); +// FontData data = fontDatas[0]; +// return new Font(Display.getCurrent(), data.getName(), data.getHeight(), data.getStyle()|SWT.BOLD); +// } + + public Font getFont(Style style) { + style = defaultIfNull(style); + if(style.isBold()) { + return JFaceResources.getFontRegistry().getBold(fFontName); + } else if(style.isUnderline()) { + return JFaceResources.getFontRegistry().getItalic(fFontName); + + } + return JFaceResources.getFontRegistry().get(fFontName); + } + + public Font getFont() { + return JFaceResources.getFontRegistry().get(fFontName); + + } + public int getFontWidth() { + return fCharSize.x; + } + public int getFontHeight() { + return fCharSize.y; + } + public void updateFont() { + updateFont(ITerminalConstants.FONT_DEFINITION); + } + /** + * Update the StyleMap for a new font name. + * The font name must be a valid name in the Jface font registry. + * @param fontName Jface name of the new font to use. + * @since 3.2 + */ + public void updateFont(String fontName) { + Display display=Display.getCurrent(); + GC gc = new GC (display); + if (JFaceResources.getFontRegistry().hasValueFor(fontName)) { + fFontName = fontName; + } else { + //fall back to "basic jface text font" + fFontName = "org.eclipse.jface.textfont"; //$NON-NLS-1$ + } + gc.setFont(getFont()); + fCharSize = gc.textExtent ("W"); //$NON-NLS-1$ + fProportional=false; + + for (char c = ' '; c <= '~'; c++) { + // consider only the first 128 chars for deciding if a font + // is proportional. Collect char width as a side-effect. + if(measureChar(gc, c, true)) + fProportional=true; + } + if(fProportional) { + // Widest char minus the padding on the left and right: + // Looks much better for small fonts + fCharSize.x-=2; + // Collect width of the upper characters (for offset calculation) + for (char c = '~'+1; c < fOffsets.length; c++) { + measureChar(gc, c,false); + } + // Calculate offsets based on each character's width and the bounding box + for (int i = ' '; i < fOffsets.length; i++) { + fOffsets[i]=(fCharSize.x-fOffsets[i])/2; + } + } else { + // Non-Proportional: Reset all offsets (eg after font change) + for (int i = 0; i < fOffsets.length; i++) { + fOffsets[i]=0; + } + String t = "The quick brown Fox jumps over the Lazy Dog."; //$NON-NLS-1$ + Point ext=gc.textExtent(t); + if(ext.x != fCharSize.x * t.length()) { + //Bug 475422: On OSX with Retina display and due to scaling, + //a text many be shorter than the sum of its bounding boxes. + //Because even with fixed width font, bounding box size + //may not be an integer but a fraction eg 6.75 pixels. + // + //Painting in proportional mode ensures that each character + //is painted individually into its proper bounding box, rather + //than using an optimization where Strings would be drawn as + //a whole. This fixes the "fractional bounding box" problem. + fProportional=true; + } + //measure font in boldface, too, and if wider then treat like proportional + gc.setFont(getFont(fDefaultStyle.setBold(true))); + Point charSizeBold = gc.textExtent("W"); //$NON-NLS-1$ + if (fCharSize.x != charSizeBold.x) { + fProportional=true; + } + } + gc.dispose (); + } + /** + * @param gc + * @param c + * @param updateMax + * @return true if the the font is proportional + */ + private boolean measureChar(GC gc, char c, boolean updateMax) { + boolean proportional=false; + Point ext=gc.textExtent(String.valueOf(c)); + if(ext.x>0 && ext.y>0 && (fCharSize.x!=ext.x || fCharSize.y!=ext.y)) { + proportional=true; + if(updateMax) { + fCharSize.x=Math.max(fCharSize.x, ext.x); + fCharSize.y=Math.max(fCharSize.y, ext.y); + } + } + fOffsets[c]=ext.x; + return proportional; + } + public boolean isFontProportional() { + return fProportional; + } + /** + * Return the offset in pixels required to center a given character + * @param c the character to measure + * @return the offset in x direction to center this character + */ + public int getCharOffset(char c) { + if(c>=fOffsets.length) + return 0; + return fOffsets[c]; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java new file mode 100644 index 00000000000..2161798bf26 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/internal/terminal/textcanvas/TextCanvas.java @@ -0,0 +1,488 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Michael Scharf (Wind River) - [240098] The cursor should not blink when the terminal is disconnected + * Uwe Stieber (Wind River) - [281328] The very first few characters might be missing in the terminal control if opened and connected programmatically + * Martin Oberhuber (Wind River) - [294327] After logging in, the remote prompt is hidden + * Anton Leherbauer (Wind River) - [294468] Fix scroller and text line rendering + * Uwe Stieber (Wind River) - [205486] Fix ScrollLock always moving to line 1 + * Anton Leherbauer (Wind River) - [219589] Copy an entire line selection + * Anton Leherbauer (Wind River) - [196465] Resizing Terminal changes Scroller location + * Anton Leherbauer (Wind River) - [324608] Terminal has strange scrolling behaviour + * Martin Oberhuber (Wind River) - [265352][api] Allow setting fonts programmatically + * Anton Leherbauer (Wind River) - [434749] UnhandledEventLoopException when copying to clipboard while the selection is empty + * Davy Landman (CWI) - [475267][api] Allow custom mouse listeners + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.events.FocusEvent; +import org.eclipse.swt.events.FocusListener; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.MouseMoveListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.internal.terminal.control.ITerminalMouseListener; + +/** + * A cell oriented Canvas. Maintains a list of "cells". + * It can either be vertically or horizontally scrolled. + * The CellRenderer is responsible for painting the cell. + */ +public class TextCanvas extends GridCanvas { + protected final ITextCanvasModel fCellCanvasModel; + /** Renders the cells */ + private final ILinelRenderer fCellRenderer; + private boolean fScrollLock; + private Point fDraggingStart; + private Point fDraggingEnd; + private boolean fHasSelection; + private ResizeListener fResizeListener; + private final List fMouseListeners; + + // The minSize is meant to determine the minimum size of the backing store + // (grid) into which remote data is rendered. If the viewport is smaller + // than that minimum size, the backing store size remains at the minSize, + // and a scrollbar is shown instead. In reality, this has the following + // issues or effects today: + // (a) Bug 281328: For very early data coming in before the widget is + // realized, the minSize determines into what initial grid that is + // rendered. See also @link{#addResizeHandler(ResizeListener)}. + // (b) Bug 294468: Since we have redraw and size computation problems + // with horizontal scrollers, for now the minColumns must be small + // enough to avoid a horizontal scroller appearing in most cases. + // (b) Bug 294327: since we have problems with the vertical scroller + // showing the correct location, minLines must be small enough + // to avoid a vertical scroller or new data may be rendered off-screen. + // As a compromise, we have been working with a 20x4 since the Terminal + // inception, though many users would want a 80x24 minSize and backing + // store. Pros and cons of the small minsize: + // + consistent "remote size==viewport size", vi works as expected + // - dumb terminals which expect 80x24 render garbled on small viewport. + // If bug 294468 were resolved, an 80 wide minSize would be preferrable + // since it allows switching the terminal viewport small/large as needed, + // without destroying the backing store. For a complete solution, + // Bug 196462 tracks the request for a user-defined fixed-widow-size-mode. + private int fMinColumns=80; + private int fMinLines=4; + private boolean fCursorEnabled; + private boolean fResizing; + + /** + * Create a new CellCanvas with the given SWT style bits. + * (SWT.H_SCROLL and SWT.V_SCROLL are automatically added). + */ + public TextCanvas(Composite parent, ITextCanvasModel model, int style,ILinelRenderer cellRenderer) { + super(parent, style | SWT.H_SCROLL | SWT.V_SCROLL); + fCellRenderer=cellRenderer; + setCellWidth(fCellRenderer.getCellWidth()); + setCellHeight(fCellRenderer.getCellHeight()); + fCellCanvasModel=model; + fCellCanvasModel.addCellCanvasModelListener(new ITextCanvasModelListener(){ + public void rangeChanged(int col, int line, int width, int height) { + if(isDisposed()) return; + repaintRange(col,line,width,height); + } + public void dimensionsChanged(int cols, int rows) { + if(isDisposed()) return; + calculateGrid(); + } + public void terminalDataChanged() { + if(isDisposed()) return; + + // scroll to end (unless scroll lock is active) + if (!fResizing) { + calculateGrid(); + scrollToEnd(); + } + } + }); + // let the cursor blink if the text canvas gets the focus... + addFocusListener(new FocusListener(){ + public void focusGained(FocusEvent e) { + fCellCanvasModel.setCursorEnabled(fCursorEnabled); + } + public void focusLost(FocusEvent e) { + fCellCanvasModel.setCursorEnabled(false); + }}); + fMouseListeners = new ArrayList(); + addMouseListener(new MouseListener(){ + public void mouseDoubleClick(MouseEvent e) { + if (fMouseListeners.size() > 0) { + Point pt = screenPointToCell(e.x, e.y); + if (pt != null) { + for (ITerminalMouseListener l : fMouseListeners) { + l.mouseDoubleClick(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button); + } + } + } + } + public void mouseDown(MouseEvent e) { + if(e.button==1) { // left button + fDraggingStart=screenPointToCell(e.x, e.y); + fHasSelection=false; + if((e.stateMask&SWT.SHIFT)!=0) { + Point anchor=fCellCanvasModel.getSelectionAnchor(); + if(anchor!=null) + fDraggingStart=anchor; + } else { + fCellCanvasModel.setSelectionAnchor(fDraggingStart); + } + fDraggingEnd=null; + } + if (fMouseListeners.size() > 0) { + Point pt = screenPointToCell(e.x, e.y); + if (pt != null) { + for (ITerminalMouseListener l : fMouseListeners) { + l.mouseDown(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button); + } + } + } + } + public void mouseUp(MouseEvent e) { + if(e.button==1) { // left button + updateHasSelection(e); + if(fHasSelection) + setSelection(screenPointToCell(e.x, e.y)); + else + fCellCanvasModel.setSelection(-1,-1,-1,-1); + fDraggingStart=null; + } + if (fMouseListeners.size() > 0) { + Point pt = screenPointToCell(e.x, e.y); + if (pt != null) { + for (ITerminalMouseListener l : fMouseListeners) { + l.mouseUp(fCellCanvasModel.getTerminalText(), pt.y, pt.x, e.button); + } + } + } + } + }); + addMouseMoveListener(new MouseMoveListener() { + + public void mouseMove(MouseEvent e) { + if (fDraggingStart != null) { + updateHasSelection(e); + setSelection(screenPointToCell(e.x, e.y)); + } + } + }); + serVerticalBarVisible(true); + setHorizontalBarVisible(false); + } + + /** + * The user has to drag the mouse to at least one character to make a selection. + * Once this is done, even a one char selection is OK. + * + * @param e + */ + private void updateHasSelection(MouseEvent e) { + if(fDraggingStart!=null) { + Point p=screenPointToCell(e.x, e.y); + if(fDraggingStart.x!=p.x||fDraggingStart.y!=p.y) + fHasSelection=true; + } + } + + void setSelection(Point p) { + if (fDraggingStart !=null && !p.equals(fDraggingEnd)) { + fDraggingEnd = p; + if (compare(p, fDraggingStart) < 0) { + // bug 219589 - make sure selection start coordinates are non-negative + int startColumn = Math.max(0, p.x); + int startRow = Math.max(p.y, 0); + fCellCanvasModel.setSelection(startRow, fDraggingStart.y, startColumn, fDraggingStart.x); + } else { + fCellCanvasModel.setSelection(fDraggingStart.y, p.y, fDraggingStart.x, p.x); + + } + } + } + + int compare(Point p1, Point p2) { + if (p1.equals(p2)) + return 0; + if (p1.y == p2.y) { + if (p1.x > p2.x) + return 1; + else + return -1; + } + if (p1.y > p2.y) { + return 1; + } else { + return -1; + } + } + public ILinelRenderer getCellRenderer() { + return fCellRenderer; + } + + public int getMinColumns() { + return fMinColumns; + } + + public void setMinColumns(int minColumns) { + fMinColumns = minColumns; + } + + public int getMinLines() { + return fMinLines; + } + + public void setMinLines(int minLines) { + fMinLines = minLines; + } + + protected void onResize(boolean init) { + if(fResizeListener!=null) { + Rectangle bonds=getClientArea(); + int cellHeight = getCellHeight(); + int cellWidth = getCellWidth(); + int lines=bonds.height/cellHeight; + int columns=bonds.width/cellWidth; + // when the view is minimised, its size is set to 0 + // we don't sent this to the terminal! + if((lines>0 && columns>0) || init) { + if(columns=fMinColumns && isHorizontalBarVisble()) { + setHorizontalBarVisible(false); + bonds=getClientArea(); + lines=bonds.height/cellHeight; + columns=bonds.width/cellWidth; + } + if(lines 0) { + y = 0; + } + Rectangle v=getViewRectangle(); + if(v.y!=-y) { + setVirtualOrigin(v.x,y); + } + // make sure the scroll area is correct: + scrollY(getVerticalBar()); + scrollX(getHorizontalBar()); + } + } + /** + * + * @return true if the cursor should be shown on output.... + */ + public boolean isScrollLock() { + return fScrollLock; + } + /** + * If set then if the size changes + */ + public void setScrollLock(boolean scrollLock) { + fScrollLock=scrollLock; + } + protected void repaintRange(int col, int line, int width, int height) { + Point origin=cellToOriginOnScreen(col,line); + Rectangle r=new Rectangle(origin.x,origin.y,width*getCellWidth(),height*getCellHeight()); + repaint(r); + } + protected void drawLine(GC gc, int line, int x, int y, int colFirst, int colLast) { + fCellRenderer.drawLine(fCellCanvasModel, gc,line,x,y,colFirst, colLast); + } + protected Color getTerminalBackgroundColor() { + return fCellRenderer.getDefaultBackgroundColor(); + } + protected void visibleCellRectangleChanged(int x, int y, int width, int height) { + fCellCanvasModel.setVisibleRectangle(y,x,height,width); + update(); + } + protected int getCols() { + return fCellCanvasModel.getTerminalText().getWidth(); + } + protected int getRows() { + return fCellCanvasModel.getTerminalText().getHeight(); + } + public String getSelectionText() { + // TODO -- create a hasSelectionMethod! + return fCellCanvasModel.getSelectedText(); + } + public void copy() { + String selectionText = getSelectionText(); + if (selectionText != null && selectionText.length() > 0) { + Clipboard clipboard = new Clipboard(getDisplay()); + clipboard.setContents(new Object[] { selectionText }, new Transfer[] { TextTransfer.getInstance() }); + clipboard.dispose(); + } + } + public void selectAll() { + fCellCanvasModel.setSelection(0, fCellCanvasModel.getTerminalText().getHeight(), 0, fCellCanvasModel.getTerminalText().getWidth()); + fCellCanvasModel.setSelectionAnchor(new Point(0,0)); + } + + /** + * @since 4.1 + */ + public void clearSelection() { + fCellCanvasModel.setSelection(-1,-1,-1,-1); + } + + /** + * Collect and return all text present in the widget. + * + *

            Individual lines of the returned text are separated by '\n'. + * + *

            The method is primarily designed for test automation. Tests need + * to check what happens in a terminal (e.g. if and how a CDT Debugger + * Console reacts in a GDB session) and this method allows to read the + * text present in the terminal. + * + * @since 4.4 + */ + public String getAllText() { + return fCellCanvasModel.getAllText(); + } + + public boolean isEmpty() { + return false; + } + /** + * Gets notified when the visible size of the terminal changes. + * This should update the model! + * + */ + public interface ResizeListener { + void sizeChanged(int lines, int columns); + } + /** + * @param listener this listener gets notified, when the size of + * the widget changed. It should change the dimensions of the underlying + * terminaldata + */ + public void addResizeHandler(ResizeListener listener) { + if(fResizeListener!=null) + throw new IllegalArgumentException("There can be at most one listener at the moment!"); //$NON-NLS-1$ + fResizeListener=listener; + + // Bug 281328: [terminal] The very first few characters might be missing in + // the terminal control if opened and connected programmatically + // + // In case the terminal had not been visible yet or is too small (less than one + // line visible), the terminal should have a minimum size to avoid RuntimeExceptions. + Rectangle bonds=getClientArea(); + if (bonds.height=getTerminalText().getHeight() || colFirst>=getTerminalText().getWidth() || colFirst-colLast==0) { + fillBackground(gc, x, y, getCellWidth()*(colLast-colFirst), getCellHeight()); + } else { + colLast=Math.min(colLast, getTerminalText().getWidth()); + LineSegment[] segments=getTerminalText().getLineSegments(line, colFirst, colLast-colFirst); + for (int i = 0; i < segments.length; i++) { + LineSegment segment=segments[i]; + Style style=segment.getStyle(); + setupGC(gc, style); + String text=segment.getText(); + drawText(gc, x, y, colFirst, segment.getColumn(), text); + drawCursor(model, gc, line, x, y, colFirst); + } + if(fModel.hasLineSelection(line)) { + gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); + gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_LIST_SELECTION)); + Point start=model.getSelectionStart(); + Point end=model.getSelectionEnd(); + char[] chars=model.getTerminalText().getChars(line); + if(chars==null) + return; + int offset=0; + if(start.y==line) + offset=start.x; + offset=Math.max(offset, colFirst); + int len; + if(end.y==line) + len=end.x-offset+1; + else + len=chars.length-offset+1; + len=Math.min(len,chars.length-offset); + if(len>0) { + String text=new String(chars,offset,len); + drawText(gc, x, y, colFirst, offset, text); + } + } + } + } + + private void fillBackground(GC gc, int x, int y, int width, int height) { + Color bg=gc.getBackground(); + gc.setBackground(getDefaultBackgroundColor()); + gc.fillRectangle (x,y,width,height); + gc.setBackground(bg); + + } + + public Color getDefaultBackgroundColor() { + // null == default style + return fStyleMap.getBackgroundColor(null); + } + + private void drawCursor(ITextCanvasModel model, GC gc, int row, int x, int y, int colFirst) { + if(!model.isCursorOn()) + return; + int cursorLine=model.getCursorLine(); + + if(row==cursorLine) { + int cursorColumn=model.getCursorColumn(); + if(cursorColumnCanvas showing a virtual object. + * Virtual: the extent of the total canvas. + * Screen: the visible client area in the screen. + */ +public abstract class VirtualCanvas extends Canvas { + + private final Rectangle fVirtualBounds = new Rectangle(0,0,0,0); + private Rectangle fClientArea; + /** + * prevent infinite loop in {@link #updateScrollbars()} + */ + private boolean fInUpdateScrollbars; + private static boolean fInUpdateScrollbarsLogged; + + public VirtualCanvas(Composite parent, int style) { + super(parent, style|SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE); + fClientArea=getClientArea(); + addListener(SWT.Paint, new Listener() { + public void handleEvent(Event event) { + paint(event.gc); + } + }); + addListener(SWT.Resize, new Listener() { + public void handleEvent(Event event) { + fClientArea=getClientArea(); + onResize(); + } + }); + getVerticalBar().addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + scrollY((ScrollBar)e.widget); + + } + + }); + getHorizontalBar().addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + scrollX((ScrollBar)e.widget); + + } + }); + } + protected void onResize() { + updateViewRectangle(); + } + protected void scrollX(ScrollBar hBar) { + int hSelection = hBar.getSelection (); + int destX = -hSelection - fVirtualBounds.x; + fVirtualBounds.x = -hSelection; + scrollSmart(destX, 0); + updateViewRectangle(); + } + protected void scrollXDelta(int delta) { + getHorizontalBar().setSelection(-fVirtualBounds.x+delta); + scrollX(getHorizontalBar()); + } + + protected void scrollY(ScrollBar vBar) { + int vSelection = vBar.getSelection (); + int destY = -vSelection - fVirtualBounds.y; + if(destY!=0) { + fVirtualBounds.y = -vSelection; + scrollSmart(0,destY); + updateViewRectangle(); + } + + } + protected void scrollYDelta(int delta) { + getVerticalBar().setSelection(-fVirtualBounds.y+delta); + scrollY(getVerticalBar()); + } + + + protected void scrollSmart(int deltaX, int deltaY) { + if (deltaX != 0 || deltaY != 0) { + Rectangle rect = getBounds(); + scroll (deltaX, deltaY, 0, 0, rect.width, rect.height, false); + } + } + + /** + * @param rect in virtual space + */ + protected void revealRect(Rectangle rect) { + Rectangle visibleRect=getScreenRectInVirtualSpace(); + // scroll the X part + int deltaX=0; + if(rect.x0||marginHeight>0){ + Color bg=getBackground(); + gc.setBackground(getTerminalBackgroundColor()); + if (marginWidth > 0) { + gc.fillRectangle (width, clipping.y, marginWidth, clipping.height); + } + if (marginHeight > 0) { + gc.fillRectangle (clipping.x, height, clipping.width, marginHeight); + } + gc.setBackground(bg); + } + } + /** + * @private + */ + protected boolean inClipping(Rectangle clipping, Rectangle r) { + // TODO check if this is OK in all cases (the <=!) + // + if(r.x+r.width<=clipping.x) + return false; + if(clipping.x+clipping.width<=r.x) + return false; + if(r.y+r.height<=clipping.y) + return false; + if(clipping.y+clipping.height<=r.y) + return false; + + return true; + } + /** + * @return the screen rect in virtual space (starting with (0,0)) + * of the visible screen. (x,y>=0) + */ + protected Rectangle getScreenRectInVirtualSpace() { + Rectangle r= new Rectangle(fClientArea.x-fVirtualBounds.x,fClientArea.y-fVirtualBounds.y,fClientArea.width,fClientArea.height); + return r; + } + /** + * @return the rect in virtual space (starting with (0,0)) + * of the visible screen. (x,y>=0) + */ + protected Rectangle getRectInVirtualSpace(Rectangle r) { + return new Rectangle(r.x-fVirtualBounds.x,r.y-fVirtualBounds.y,r.width,r.height); + } + + /** + * Sets the extent of the virtual display area + * @param width width of the display area + * @param height height of the display area + */ + protected void setVirtualExtend(int width, int height) { + fVirtualBounds.width=width; + fVirtualBounds.height=height; + updateScrollbars(); + updateViewRectangle(); + } + /** + * sets the scrolling origin. Also sets the scrollbars. + * Does NOT redraw! + * Use negative values (move the virtual origin to the top left + * to see something in the screen (which is located at (0,0)) + * @param x + * @param y + */ + protected void setVirtualOrigin(int x, int y) { + if (fVirtualBounds.x != x || fVirtualBounds.y != y) { + fVirtualBounds.x=x; + fVirtualBounds.y=y; + getHorizontalBar().setSelection(-x); + getVerticalBar().setSelection(-y); + updateViewRectangle(); + } + } + protected Rectangle getVirtualBounds() { + return cloneRectangle(fVirtualBounds); + } + /** + * @param x + * @return the virtual coordinate in screen space + */ + protected int virtualXtoScreen(int x) { + return x+fVirtualBounds.x; + } + protected int virtualYtoScreen(int y) { + return y+fVirtualBounds.y; + } + protected int screenXtoVirtual(int x) { + return x-fVirtualBounds.x; + } + protected int screenYtoVirtual(int y) { + return y-fVirtualBounds.y; + } + /** called when the viewed part is changing */ + private final Rectangle fViewRectangle=new Rectangle(0,0,0,0); + protected void updateViewRectangle() { + if( + fViewRectangle.x==-fVirtualBounds.x + && fViewRectangle.y==-fVirtualBounds.y + && fViewRectangle.width==fClientArea.width + && fViewRectangle.height==fClientArea.height + ) + return; + fViewRectangle.x=-fVirtualBounds.x; + fViewRectangle.y=-fVirtualBounds.y; + fViewRectangle.width=fClientArea.width; + fViewRectangle.height=fClientArea.height; + viewRectangleChanged(fViewRectangle.x,fViewRectangle.y,fViewRectangle.width,fViewRectangle.height); + } + protected Rectangle getViewRectangle() { + return cloneRectangle(fViewRectangle); + } + private Rectangle cloneRectangle(Rectangle r) { + return new Rectangle(r.x,r.y,r.width,r.height); + } + /** + * Called when the viewed part has changed. + * Override when you need this information.... + * Is only called if the values change! + * @param x visible in virtual space + * @param y visible in virtual space + * @param width + * @param height + */ + protected void viewRectangleChanged(int x, int y, int width, int height) { + } + /** + * @private + */ + private void updateScrollbars() { + // don't get into infinite loops.... + if(!fInUpdateScrollbars) { + fInUpdateScrollbars=true; + try { + doUpdateScrollbar(); + } finally { + fInUpdateScrollbars=false; + } + } else { + if(!fInUpdateScrollbarsLogged) { + fInUpdateScrollbarsLogged=true; + TerminalPlugin.getDefault().getLog().log(new Status(IStatus.WARNING, + TerminalPlugin.PLUGIN_ID, IStatus.OK, "Unexpected Recursion in terminal", //$NON-NLS-1$ + new RuntimeException())); + } + } + } + private void doUpdateScrollbar() { + Rectangle clientArea= getClientArea(); + ScrollBar horizontal= getHorizontalBar(); + // even if setVisible was called on the scrollbar, isVisible + // returns false if its parent is not visible. + if(!isVisible() || horizontal.isVisible()) { + horizontal.setPageIncrement(clientArea.width - horizontal.getIncrement()); + int max= fVirtualBounds.width; + horizontal.setMaximum(max); + horizontal.setThumb(clientArea.width); + } + ScrollBar vertical= getVerticalBar(); + // even if setVisible was called on the scrollbar, isVisible + // returns false if its parent is not visible. + if(!isVisible() || vertical.isVisible()) { + vertical.setPageIncrement(clientArea.height - vertical.getIncrement()); + int max= fVirtualBounds.height; + vertical.setMaximum(max); + vertical.setThumb(clientArea.height); + } + } + protected boolean isVertialBarVisible() { + return getVerticalBar().isVisible(); + } + protected void serVerticalBarVisible(boolean showVScrollBar) { + ScrollBar vertical= getVerticalBar(); + vertical.setVisible(showVScrollBar); + vertical.setSelection(0); + } + protected boolean isHorizontalBarVisble() { + return getHorizontalBar().isVisible(); + } + protected void setHorizontalBarVisible(boolean showHScrollBar) { + ScrollBar horizontal= getHorizontalBar(); + horizontal.setVisible(showHScrollBar); + horizontal.setSelection(0); + } +} + diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextData.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextData.java new file mode 100644 index 00000000000..83e5e9568e1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextData.java @@ -0,0 +1,152 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [261486][api][cleanup] Mark @noimplement interfaces as @noextend + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +/** + * A writable matrix of characters and {@link Style}. This is intended to be the + * low level representation of the text of a Terminal. Higher layers are + * responsible to fill the text and styles into this representation. + *

            + * Note: Implementations of this interface has to be thread safe. + *

            + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ITerminalTextData extends ITerminalTextDataReadOnly { + + /** + * Sets the dimensions of the data. If the dimensions are smaller than the current + * dimensions, the lines will be chopped. If the dimensions are bigger, then + * the new elements will be filled with 0 chars and null Style. + * @param height + * @param width + */ + void setDimensions(int height, int width); + + void setMaxHeight(int height); + int getMaxHeight(); + + /** + * Set a single character and the associated {@link Style}. + * @param line line must be >=0 and < height + * @param column column must be >=0 and < width + * @param c the new character at this position + * @param style the style or null + */ + void setChar(int line, int column, char c, Style style); + + /** + * Set an array of characters showing in the same {@link Style}. + * @param line line must be >=0 and < height + * @param column column must be >=0 and < width + * @param chars the new characters at this position + * @param style the style or null + */ + void setChars(int line, int column, char[] chars, Style style); + + /** + * Set a subrange of an array of characters showing in the same {@link Style}. + * @param line line must be >=0 and < height + * @param column column must be >=0 and < width + * @param chars the new characters at this position + * @param start the start index in the chars array + * @param len the number of characters to insert. Characters beyond width are not inserted. + * @param style the style or null + */ + void setChars(int line, int column, char[] chars, int start, int len, Style style); + + + /** + * Cleans the entire line. + * @param line + */ + void cleanLine(int line); + + /** + * Shifts some lines up or down. The "empty" space is filled with '\000' chars + * and null {@link Style} + *

            To illustrate shift, here is some sample data: + *

            +	 * 0 aaaa
            +	 * 1 bbbb
            +	 * 2 cccc
            +	 * 3 dddd
            +	 * 4 eeee
            +	 * 
            + * + * Shift a region of 3 lines up by one line shift(1,3,-1) + *
            +	 * 0 aaaa
            +	 * 1 cccc
            +	 * 2 dddd
            +	 * 3
            +	 * 4 eeee
            +	 * 
            + * + * + * Shift a region of 3 lines down by one line shift(1,3,1) + *
            +	 * 0 aaaa
            +	 * 1
            +	 * 2 bbbb
            +	 * 3 cccc
            +	 * 4 eeee
            +	 * 
            + * @param startLine the start line of the shift + * @param size the number of lines to shift + * @param shift how much scrolling is done. New scrolled area is filled with '\000'. + * Negative number means scroll down, positive scroll up (see example above). + */ + void scroll(int startLine, int size, int shift); + + /**Adds a new line to the terminal. If maxHeigth is reached, the entire terminal + * will be scrolled. Else a line will be added. + */ + void addLine(); + /** + * Copies the entire source into this and changes the size accordingly + * @param source + */ + void copy(ITerminalTextData source); + /** + * Copy a sourceLine from source to this at destLine. + * @param source + * @param sourceLine + * @param destLine + */ + void copyLine(ITerminalTextData source,int sourceLine, int destLine); + /** + * Copy length lines from source starting at sourceLine into this starting at + * destLine. + * @param source + * @param sourceStartLine + * @param destStartLine + * @param length + */ + void copyRange(ITerminalTextData source, int sourceStartLine, int destStartLine,int length); + + void setCursorLine(int line); + void setCursorColumn(int column); + + /** + * Makes this line a wrapped line which logically continues on next line. + * + * @param line + * @since 3.3 + */ + void setWrappedLine(int line); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextDataReadOnly.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextDataReadOnly.java new file mode 100644 index 00000000000..21a4870caaf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextDataReadOnly.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [261486][api][cleanup] Mark @noimplement interfaces as @noextend + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +/** + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ITerminalTextDataReadOnly { + + /** + * @return the width of the terminal + */ + int getWidth(); + + /** + * @return the height of the terminal + */ + int getHeight(); + + /** + * @param line be >=0 and < height + * @param startCol must be >=0 and < width + * @param numberOfCols must be > 0 + * @return a the line segments of the specified range + */ + LineSegment[] getLineSegments(int line, int startCol, int numberOfCols); + + /** + * @param line must be >=0 and < height + * @param column must be >=0 and < width + * @return the character at column,line + */ + char getChar(int line, int column); + + /** + * @param line must be >=0 and < height + * @param column must be >=0 and < width + * @return style at column,line or null + */ + Style getStyle(int line, int column); + + /** + * Creates a new instance of {@link ITerminalTextDataSnapshot} that + * can be used to track changes. Make sure to call {@link ITerminalTextDataSnapshot#detach()} + * if you don't need the snapshots anymore. + *

            Note: A new snapshot is empty and needs a call to {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)} to + * get its initial values. You might want to setup the snapshot to your needs by calling + * {@link ITerminalTextDataSnapshot#setInterestWindow(int, int)}. + *

            + * @return a new instance of {@link ITerminalTextDataSnapshot} that "listens" to changes of + * this. + */ + public ITerminalTextDataSnapshot makeSnapshot(); + + char[] getChars(int line); + Style[] getStyles(int line); + + /** + * @return the line in which the cursor is at the moment + */ + int getCursorLine(); + /** + * @return the column at which the cursor is at the moment + */ + int getCursorColumn(); + + /** + * @param line + * @return true if this line got wrapped, ie. logically continues on next line + * @since 3.3 + */ + boolean isWrappedLine(int line); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextDataSnapshot.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextDataSnapshot.java new file mode 100644 index 00000000000..47c7ee4cb57 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/ITerminalTextDataSnapshot.java @@ -0,0 +1,228 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [261486][api][cleanup] Mark @noimplement interfaces as @noextend + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +/** + * This class maintains a snapshot of an instance of {@link ITerminalTextData}. + * While the {@link ITerminalTextData} continues changing, the snapshot remains + * unchanged until the next snapshot is taken by calling + * {@link #updateSnapshot(boolean)}. This is important, because the + * {@link ITerminalTextData} might get modified by another thread. Suppose you + * would want to draw the content of the {@link ITerminalTextData} using the + * following loop: + * + *
            + * for (int line = 0; line < term.getHeight(); line++)
            + * 	for (int column = 0; column < term.getWidth(); column++)
            + * 		drawCharacter(column, line, term.getChar(column, line), term.getStyle(column, line));
            + * 
            + * + * This might fail because the background thread could change the dimensions of + * the {@link ITerminalTextData} while you iterate the loop. One solution would + * be to put a synchronized(term){} statement around the code. This + * has two problems: 1. you would have to know about the internals of the + * synchronisation of {@link ITerminalTextData}. 2. The other thread that + * changes {@link ITerminalTextData} is blocked while the potentially slow + * drawing is done. + *

            + * Solution: Take a snapshot of the terminal and use the snapshot to draw + * the content. There is no danger that the data structure get changed while you + * draw. There are also methods to find out what has changed to minimize the + * number of lines that get redrawn. + *

            + * + *

            + * Drawing optimization: To optimize redrawing of changed lines, this + * class keeps track of lines that have changed since the previous snapshot. + *

            + * + *
            + * // iterate over the potentially changed lines
            + * for (int line = snap.getFirstChangedLine(); line <= snap.getLastChangedLine(); line++)
            + * 	// redraw only if the line has changed
            + * 	if (snap.hasLineChanged(line))
            + * 		for (int column = 0; column < snap.getWidth(); column++)
            + * 			drawCharacter(column, line, snap.getChar(column, line), snap.getStyle(column, line));
            + * 
            + * + *

            + * Scroll optimization: Often new lines are appended at the bottom of the + * terminal and the rest of the lines are scrolled up. In this case all lines + * would be marked as changed. To optimize for this case, + * {@link #updateSnapshot(boolean)} can be called with true for the + * detectScrolling parameter. The object will keep track of + * scrolling. The UI must first handle the scrolling and then use the + * {@link #hasLineChanged(int)} method to determine scrolling: + * + *

            + * // scroll the visible region of the UI <b>before</b> drawing the changed lines.
            + * doUIScrolling(snap.getScrollChangeY(), snap.getScrollChangeN(), snap.getScrollChangeShift());
            + * // iterate over the potentially changed lines
            + * for (int line = snap.getFirstChangedLine(); line <= snap.getFirstChangedLine(); line++)
            + * 	// redraw only if the line has changed
            + * 	if (snap.hasLineChanged(line))
            + * 		for (int column = 0; column < snap.getWidth(); column++)
            + * 			drawCharacter(column, line, snap.getChar(column, line), snap.getStyle(column, line));
            + * 
            + * + *

            + *

            + * Threading Note: This class is not thread safe! All methods have to be + * called by the a same thread, that created the instance by calling + * {@link ITerminalTextDataReadOnly#makeSnapshot()}. + *

            + * + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. + */ +public interface ITerminalTextDataSnapshot extends ITerminalTextDataReadOnly { + /** + * This listener gets called when the current snapshot + * is out of date. Calling {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)} + * will have an effect. Once the {@link #snapshotOutOfDate(ITerminalTextDataSnapshot)} method is called, + * it will not be called until {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)} + * is called and a new snapshot needs to be updated again. + *

            + * A typical terminal view would not update the snapshot immediately + * after the {@link #snapshotOutOfDate(ITerminalTextDataSnapshot)} has been called. It would introduce a + * delay to update the UI (and the snapshot} 10 or 20 times per second. + * + *

            Make sure you don't spend too much time in this method. + */ + interface SnapshotOutOfDateListener { + /** + * Gets called when the snapshot is out of date. To get the snapshot up to date, + * call {@link ITerminalTextDataSnapshot#updateSnapshot(boolean)}. + * @param snapshot The snapshot that is out of date + */ + void snapshotOutOfDate(ITerminalTextDataSnapshot snapshot); + } + void addListener(SnapshotOutOfDateListener listener); + void removeListener(SnapshotOutOfDateListener listener); + + /** + * Ends the listening to the {@link ITerminalTextData}. After this + * has been called no new snapshot data is collected. + */ + void detach(); + /** + * @return true if the data has changed since the previous snapshot. + */ + boolean isOutOfDate(); + + /** + * The window of interest is the region the snapshot should track. + * Changes outside this region are ignored. The change takes effect after + * an update! + * @param startLine -1 means track the end of the data + * @param size number of lines to track. A size of -1 means track all. + */ + void setInterestWindow(int startLine, int size); + int getInterestWindowStartLine(); + int getInterestWindowSize(); + + /** + * Create a new snapshot of the {@link ITerminalTextData}. It will efficiently + * copy the data of the {@link ITerminalTextData} into an internal representation. + * The snapshot also keeps track of the changes since the previous snapshot. + *

            With the methods {@link #getFirstChangedLine()}, {@link #getLastChangedLine()} and + * {@link #hasLineChanged(int)} + * you can find out what has changed in the current snapshot since the previous snapshot. + * @param detectScrolling if true the snapshot tries to identify scroll + * changes since the last snapshot. In this case the information about scrolling + * can be retrieved using the following methods: + * {@link #getScrollWindowStartLine()}, {@link #getScrollWindowSize()} and {@link #getScrollWindowShift()} + *
            Note: The method {@link #hasLineChanged(int)} returns changes after the + * scrolling has been applied. + */ + void updateSnapshot(boolean detectScrolling); + + /** + * @return The first line changed in this snapshot compared + * to the previous snapshot. + * + *

            Note: If no line has changed, this + * returns {@link Integer#MAX_VALUE} + * + *

            Note: if {@link #updateSnapshot(boolean)} has been called with true, + * then this does not include lines that only have been scrolled. This is the + * first line that has changed after the scroll has been applied. + */ + int getFirstChangedLine(); + + /** + * @return The last line changed in this snapshot compared + * to the previous snapshot. If the height has changed since the + * last update of the snapshot, then the returned value is within + * the new dimensions. + * + *

            Note: If no line has changed, this returns -1 + * + *

            Note: if {@link #updateSnapshot(boolean)} has been called with true, + * then this does not include lines that only have been scrolled. This is the + * last line that has changed after the scroll has been applied. + * + *

            A typical for loop using this method would look like this (note the <= in the for loop): + *

            +	 * for(int line=snap.{@link #getFirstChangedLine()}; line <= snap.getLastChangedLine(); line++)
            +	 *    if(snap.{@link #hasLineChanged(int) hasLineChanged(line)})
            +	 *       doSomething(line);
            +	 * 
            + */ + int getLastChangedLine(); + + /** + * @param line + * @return true if the line has changed since the previous snapshot + */ + boolean hasLineChanged(int line); + + boolean hasDimensionsChanged(); + + /** + * @return true if the terminal has changed (and not just the + * window of interest) + */ + boolean hasTerminalChanged(); + /** + * If {@link #updateSnapshot(boolean)} was called with true, then this method + * returns the top of the scroll region. + * @return The first line scrolled in this snapshot compared + * to the previous snapshot. See also {@link ITerminalTextData#scroll(int, int, int)}. + */ + int getScrollWindowStartLine(); + + /** + * If {@link #updateSnapshot(boolean)} was called with true, then this method + * returns the size of the scroll region. + * @return The number of lines scrolled in this snapshot compared + * to the previous snapshot. See also {@link ITerminalTextData#scroll(int, int, int)} + * If nothing has changed, 0 is returned. + */ + int getScrollWindowSize(); + + /** + * If {@link #updateSnapshot(boolean)} was called with true, then this method + * returns number of lines moved by the scroll region. + * @return The the scroll shift of this snapshot compared + * to the previous snapshot. See also {@link ITerminalTextData#scroll(int, int, int)} + */ + int getScrollWindowShift(); + + /** + * @return The {@link ITerminalTextData} on that this instance is observing. + */ + ITerminalTextData getTerminalTextData(); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/LineSegment.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/LineSegment.java new file mode 100644 index 00000000000..7381d0e6439 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/LineSegment.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + + +public class LineSegment { + private final String fText; + private final int fCol; + private final Style fStyle; + public LineSegment(int col, String text, Style style) { + fCol = col; + fText = text; + fStyle = style; + } + public Style getStyle() { + return fStyle; + } + public String getText() { + return fText; + } + public int getColumn() { + return fCol; + } + public String toString() { + return "LineSegment("+fCol+", \""+fText+"\","+fStyle+")"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/Style.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/Style.java new file mode 100644 index 00000000000..fa7be137653 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/Style.java @@ -0,0 +1,154 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author scharf + * Flyweight + * Threadsafe. + * + */ +// TODO add an Object for user data, use weak map to keep track of styles with associated +// user data +public class Style { + private final StyleColor fForground; + private final StyleColor fBackground; + private final boolean fBold; + private final boolean fBlink; + private final boolean fUnderline; + private final boolean fReverse; + private final static Map fgStyles=new HashMap(); + private Style(StyleColor forground, StyleColor background, boolean bold, boolean blink, boolean underline, boolean reverse) { + fForground = forground; + fBackground = background; + fBold = bold; + fBlink = blink; + fUnderline = underline; + fReverse = reverse; + } + public static Style getStyle(StyleColor forground, StyleColor background, boolean bold, boolean blink, boolean underline, boolean reverse) { + Style style = new Style(forground,background, bold, blink,underline,reverse); + Style cached; + synchronized (fgStyles) { + cached=fgStyles.get(style); + if(cached==null) { + cached=style; + fgStyles.put(cached, cached); + } + } + return cached; + } + public static Style getStyle(String forground, String background) { + return getStyle(StyleColor.getStyleColor(forground), StyleColor.getStyleColor(background),false,false,false,false); + } + public static Style getStyle(StyleColor forground, StyleColor background) { + return getStyle(forground, background,false,false,false,false); + } + public Style setForground(StyleColor forground) { + return getStyle(forground,fBackground,fBold,fBlink,fUnderline,fReverse); + } + public Style setBackground(StyleColor background) { + return getStyle(fForground,background,fBold,fBlink,fUnderline,fReverse); + } + public Style setForground(String colorName) { + return getStyle(StyleColor.getStyleColor(colorName),fBackground,fBold,fBlink,fUnderline,fReverse); + } + public Style setBackground(String colorName) { + return getStyle(fForground,StyleColor.getStyleColor(colorName),fBold,fBlink,fUnderline,fReverse); + } + public Style setBold(boolean bold) { + return getStyle(fForground,fBackground,bold,fBlink,fUnderline,fReverse); + } + public Style setBlink(boolean blink) { + return getStyle(fForground,fBackground,fBold,blink,fUnderline,fReverse); + } + public Style setUnderline(boolean underline) { + return getStyle(fForground,fBackground,fBold,fBlink,underline,fReverse); + } + public Style setReverse(boolean reverse) { + return getStyle(fForground,fBackground,fBold,fBlink,fUnderline,reverse); + } + public StyleColor getBackground() { + return fBackground; + } + public boolean isBlink() { + return fBlink; + } + public boolean isBold() { + return fBold; + } + public StyleColor getForground() { + return fForground; + } + public boolean isReverse() { + return fReverse; + } + public boolean isUnderline() { + return fUnderline; + } + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((fBackground == null) ? 0 : fBackground.hashCode()); + result = prime * result + (fBlink ? 1231 : 1237); + result = prime * result + (fBold ? 1231 : 1237); + result = prime * result + ((fForground == null) ? 0 : fForground.hashCode()); + result = prime * result + (fReverse ? 1231 : 1237); + result = prime * result + (fUnderline ? 1231 : 1237); + return result; + } + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final Style other = (Style) obj; + // background == is the same as equals + if (fBackground != other.fBackground) + return false; + if (fBlink != other.fBlink) + return false; + if (fBold != other.fBold) + return false; + if (fForground != other.fForground) + return false; + if (fReverse != other.fReverse) + return false; + if (fUnderline != other.fUnderline) + return false; + return true; + } + public String toString() { + StringBuffer result=new StringBuffer(); + result.append("Style(foreground="); //$NON-NLS-1$ + result.append(fForground); + result.append(", background="); //$NON-NLS-1$ + result.append(fBackground); + if(fBlink) + result.append(", blink"); //$NON-NLS-1$ + if(fBold) + result.append(", bold"); //$NON-NLS-1$ + if(fBlink) + result.append(", blink"); //$NON-NLS-1$ + if(fReverse) + result.append(", reverse"); //$NON-NLS-1$ + if(fUnderline) + result.append(", underline"); //$NON-NLS-1$ + result.append(")"); //$NON-NLS-1$ + return result.toString(); + } + +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/StyleColor.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/StyleColor.java new file mode 100644 index 00000000000..10e1ed55096 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/StyleColor.java @@ -0,0 +1,54 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +import java.util.HashMap; +import java.util.Map; + +/** + * + * Flyweight + * Threadsafe. + */ +public class StyleColor { + private final static Map fgStyleColors=new HashMap(); + final String fName; + + /** + * @param name the name of the color. It is up to the UI to associate a + * named color with a visual representation + * @return a StyleColor + */ + public static StyleColor getStyleColor(String name) { + StyleColor result; + synchronized (fgStyleColors) { + result=fgStyleColors.get(name); + if(result==null) { + result=new StyleColor(name); + fgStyleColors.put(name, result); + } + } + return result; + } + // nobody except the factory method is allowed to instantiate this class! + private StyleColor(String name) { + fName = name; + } + + public String getName() { + return fName; + } + + public String toString() { + return fName; + } + // no need to override equals and hashCode, because Object uses object identity +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/TerminalTextDataFactory.java b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/TerminalTextDataFactory.java new file mode 100644 index 00000000000..2877c4d0631 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.control/src/org/eclipse/tm/terminal/model/TerminalTextDataFactory.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +import org.eclipse.tm.internal.terminal.model.SynchronizedTerminalTextData; +import org.eclipse.tm.internal.terminal.model.TerminalTextData; + +public class TerminalTextDataFactory { + static public ITerminalTextData makeTerminalTextData() { + return new SynchronizedTerminalTextData(new TerminalTextData()); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.control/tm32.png b/terminal/plugins/org.eclipse.tm.terminal.control/tm32.png new file mode 100644 index 00000000000..668b05b7913 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.control/tm32.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/.classpath b/terminal/plugins/org.eclipse.tm.terminal.test/.classpath new file mode 100644 index 00000000000..9c8ffa9fe2c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/.classpath @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/.cvsignore b/terminal/plugins/org.eclipse.tm.terminal.test/.cvsignore new file mode 100644 index 00000000000..ba077a4031a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/.cvsignore @@ -0,0 +1 @@ +bin diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.test/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/.project b/terminal/plugins/org.eclipse.tm.terminal.test/.project new file mode 100644 index 00000000000..492f603b4c0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/.project @@ -0,0 +1,28 @@ + + + org.eclipse.tm.terminal.test + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.test/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..ac97a9dfa02 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,69 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +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=ignore +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=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=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +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.unusedParameterIncludeDocCommentReference=enabled +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.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.test/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..ee4d19bfbf0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.test;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Vendor: %providerName +Bundle-Localization: plugin +Require-Bundle: org.junit, + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.core.runtime, + org.eclipse.ui +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Export-Package: org.eclipse.tm.internal.terminal.connector;x-internal:=true, + org.eclipse.tm.internal.terminal.emulator;x-internal:=true, + org.eclipse.tm.internal.terminal.model;x-internal:=true, + org.eclipse.tm.internal.terminal.speedtest;x-internal:=true, + org.eclipse.tm.internal.terminal.test.terminalcanvas;x-internal:=true, + org.eclipse.tm.internal.terminal.test.ui;x-internal:=true, + org.eclipse.tm.internal.terminal.textcanvas;x-internal:=true, + org.eclipse.tm.terminal.model, + org.eclipse.tm.terminal.test diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/about.html b/terminal/plugins/org.eclipse.tm.terminal.test/about.html new file mode 100644 index 00000000000..80e5d5c671b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/about.html @@ -0,0 +1,29 @@ + + + + +About + + +

            About This Content

            + +

            June 5, 2007

            +

            License

            + +

            The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

            + +

            If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

            + + + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/about.ini b/terminal/plugins/org.eclipse.tm.terminal.test/about.ini new file mode 100644 index 00000000000..3adc27ab587 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/about.ini @@ -0,0 +1,27 @@ +# about.ini +# contains information about a feature +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# "%key" are externalized strings defined in about.properties +# This file does not need to be translated. + +# Property "aboutText" contains blurb for "About" dialog (translated) +aboutText=%blurb + +# Property "windowImage" contains path to window icon (16x16) +# needed for primary features only + +# Property "featureImage" contains path to feature image (32x32) +featureImage=tm32.png + +# Property "aboutImage" contains path to product image (500x330 or 115x164) +# needed for primary features only + +# Property "appName" contains name of the application (not translated) +# needed for primary features only + +# Property "welcomePage" contains path to welcome page (special XML-based format) +# optional + +# Property "welcomePerspective" contains the id of the perspective in which the +# welcome page is to be opened. +# optional \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/about.properties b/terminal/plugins/org.eclipse.tm.terminal.test/about.properties new file mode 100644 index 00000000000..bd810e7c32b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/about.properties @@ -0,0 +1,26 @@ +############################################################################### +# Copyright (c) 2007, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# IBM Corporation - initial API and implementation +############################################################################### +# about.properties +# contains externalized strings for about.ini +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# fill-ins are supplied by about.mappings +# This file should be translated. +# +# Do not translate any values surrounded by {} + +blurb=TM Terminal Unit Tests\n\ +\n\ +Version: {featureVersion}\n\ +\n\ +(c) Copyright Wind River Systems, Inc. and others 2007, 2017. All rights reserved.\n\ +Visit http://www.eclipse.org/tm diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/build.properties b/terminal/plugins/org.eclipse.tm.terminal.test/build.properties new file mode 100644 index 00000000000..8ae28497147 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/build.properties @@ -0,0 +1,24 @@ +############################################################################### +# Copyright (c) 2007, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + plugin.xml,\ + about.properties,\ + about.ini,\ + tm32.png,\ + about.html +src.includes = teamConfig/,\ + about.html diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.test/plugin.properties new file mode 100644 index 00000000000..6e7dd7dad2d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/plugin.properties @@ -0,0 +1,19 @@ +############################################################################### +# Copyright (c) 2007, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Initial Contributors: +# The following Wind River employees contributed to the Terminal component +# that contains this file: Chris Thew, Fran Litterio, Stephen Lamb, +# Helmut Haigermoser and Ted Williams. +# +# Contributors: +# Michael Scharf (Wind River) - initial API and implementation +############################################################################### +pluginName = Target Management Terminal Tests +providerName = Eclipse.org - Target Management diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.test/plugin.xml new file mode 100644 index 00000000000..def334de009 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/plugin.xml @@ -0,0 +1,24 @@ + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.test/pom.xml new file mode 100644 index 00000000000..cb0115da7dc --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/pom.xml @@ -0,0 +1,194 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.test + eclipse-test-plugin + + + true + -ea -Xmx512m -XX:MaxPermSize=256m -Drse.enableSecureStoreAccess=false -Dorg.eclipse.swt.browser.UseWebKitGTK=true + + + + + tests + + + + + org.eclipse.tycho + tycho-surefire-plugin + ${tycho-version} + + true + false + org.eclipse.platform.ide + + + ${tycho.testArgLine} ${ui.test.vmargs} + org.eclipse.ui.ide.workbench + true + true + p2Installed + + + ${basedir}/tracing/.options + + + + + **/AutomatedPluginTests.* + **/AutomatedTests.* + + + + + + org.codehaus.gmaven + gmaven-plugin + + + validate + + execute + + + + project.properties['qualified.bundle.version'] = project.properties['unqualifiedVersion'].replace('qualifier', project.properties['buildQualifier']) + + + + + + + + org.apache.maven.plugins + maven-antrun-plugin + + + generate-report + post-integration-test + + run + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.jacoco + org.jacoco.ant + ${jacoco-version} + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java new file mode 100644 index 00000000000..0edbe8b80b6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorFactoryTest.java @@ -0,0 +1,275 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + * Martin Oberhuber (Wind River) - [204796] Terminal should allow setting the encoding to use + * Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.connector; + +import java.io.OutputStream; + +import junit.framework.TestCase; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +public class TerminalConnectorFactoryTest extends TestCase { + public class SettingsMock implements ISettingsStore { + + public String get(String key) { + return null; + } + + public String get(String key, String defaultValue) { + return null; + } + + public void put(String key, String value) { + } + + } + public static class TerminalControlMock implements ITerminalControl { + + public void setEncoding(String encoding) { + } + + public String getEncoding() { + return "ISO-8859-1"; //$NON-NLS-1$ + } + + public void displayTextInTerminal(String text) { + } + + public OutputStream getRemoteToTerminalOutputStream() { + return null; + } + + public Shell getShell() { + return null; + } + + public TerminalState getState() { + return null; + } + + public void setMsg(String msg) { + } + + public void setState(TerminalState state) { + } + + public void setTerminalTitle(String title) { + } + + public void setupTerminal(Composite parent) { + } + + public boolean isConnectOnEnterIfClosed() { + return false; + } + + public void setConnectOnEnterIfClosed(boolean on) { + } + + public void setVT100LineWrapping(boolean enable) { + } + + public boolean isVT100LineWrapping() { + return false; + } + } + static class ConnectorMock extends TerminalConnectorImpl { + + public boolean fEcho; + public int fWidth; + public int fHeight; + public ITerminalControl fTerminalControl; + public ISettingsStore fSaveStore; + public ISettingsStore fLoadStore; + public boolean fDisconnect; + + public boolean isLocalEcho() { + return fEcho; + } + public void setTerminalSize(int newWidth, int newHeight) { + fWidth=newWidth; + fHeight=newHeight; + } + public void connect(ITerminalControl control) { + super.connect(control); + fTerminalControl = control; + } + public void doDisconnect() { + fDisconnect=true; + } + + public OutputStream getTerminalToRemoteStream() { + return null; + } + + public String getSettingsSummary() { + return "Summary"; + } + + public void load(ISettingsStore store) { + fLoadStore=store; + } + + public void save(ISettingsStore store) { + fSaveStore=store; + } + } + protected TerminalConnector makeTerminalConnector() { + return makeTerminalConnector(new ConnectorMock()); + } + + protected TerminalConnector makeTerminalConnector(final TerminalConnectorImpl mock) { + TerminalConnector c=new TerminalConnector(new TerminalConnector.Factory(){ + public TerminalConnectorImpl makeConnector() throws Exception { + return mock; + } + },"xID","xName", false); + return c; + } + + public void testGetInitializationErrorMessage() { + TerminalConnector c=makeTerminalConnector(); + c.connect(new TerminalControlMock()); + assertNull(c.getInitializationErrorMessage()); + + c=makeTerminalConnector(new ConnectorMock(){ + public void initialize() throws Exception { + throw new Exception("FAILED"); + }}); + c.connect(new TerminalControlMock()); + assertEquals("FAILED",c.getInitializationErrorMessage()); + + } + + public void testGetIdAndName() { + TerminalConnector c=makeTerminalConnector(); + assertEquals("xID", c.getId()); + assertEquals("xName", c.getName()); + } + + public void testIsInitialized() { + TerminalConnector c=makeTerminalConnector(); + assertFalse(c.isInitialized()); + c.getId(); + assertFalse(c.isInitialized()); + c.getName(); + assertFalse(c.isInitialized()); + c.getSettingsSummary(); + assertFalse(c.isInitialized()); + c.setTerminalSize(10,10); + assertFalse(c.isInitialized()); + c.load(null); + assertFalse(c.isInitialized()); + c.save(null); + assertFalse(c.isInitialized()); + if (!Platform.isRunning()) return; + c.getAdapter(ConnectorMock.class); + assertFalse(c.isInitialized()); + } + + public void testConnect() { + TerminalConnector c=makeTerminalConnector(); + assertFalse(c.isInitialized()); + c.connect(new TerminalControlMock()); + assertTrue(c.isInitialized()); + + } + + public void testDisconnect() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + TerminalControlMock control=new TerminalControlMock(); + c.connect(control); + c.disconnect(); + assertTrue(mock.fDisconnect); + } + + public void testGetTerminalToRemoteStream() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + TerminalControlMock control=new TerminalControlMock(); + c.connect(control); + assertSame(mock.fTerminalControl,control); + } + public void testGetSettingsSummary() { + TerminalConnector c=makeTerminalConnector(); + assertEquals("Not Initialized", c.getSettingsSummary()); + c.connect(new TerminalControlMock()); + assertEquals("Summary", c.getSettingsSummary()); + } + + public void testIsLocalEcho() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + assertFalse(c.isLocalEcho()); + mock.fEcho=true; + assertTrue(c.isLocalEcho()); + } + + public void testLoad() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + ISettingsStore s=new SettingsMock(); + c.load(s); + // the load is called after the connect... + assertNull(mock.fLoadStore); + c.connect(new TerminalControlMock()); + assertSame(s,mock.fLoadStore); + } + + public void testSave() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + ISettingsStore s=new SettingsMock(); + c.save(s); + assertNull(mock.fSaveStore); + c.connect(new TerminalControlMock()); + c.save(s); + assertSame(s,mock.fSaveStore); + } + + public void testSetDefaultSettings() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + c.setDefaultSettings(); + } + + public void testSetTerminalSize() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + c.setTerminalSize(100, 200); + + } + + public void testGetAdapter() { + if (!Platform.isRunning()) return; + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c = makeTerminalConnector(mock); + assertNull(c.getAdapter(ConnectorMock.class)); + // the load is called after the connect... + c.connect(new TerminalControlMock()); + + assertSame(mock, c.getAdapter(ConnectorMock.class)); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorPluginTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorPluginTest.java new file mode 100644 index 00000000000..68e98bb2606 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorPluginTest.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + * Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + *******************************************************************************/ + +package org.eclipse.tm.internal.terminal.connector; + +import junit.framework.TestCase; + +import org.eclipse.core.runtime.Platform; +import org.eclipse.tm.internal.terminal.connector.TerminalConnectorTest.ConnectorMock; +import org.eclipse.tm.internal.terminal.connector.TerminalConnectorTest.SimpleFactory; +import org.eclipse.tm.internal.terminal.connector.TerminalConnectorTest.TerminalControlMock; + +/** + * Testcase for TerminalConnector that must run as a JUnit plug-in test. + */ +public class TerminalConnectorPluginTest extends TestCase { + + public void testIsInitialized() { + if (!Platform.isRunning()) + return; + TerminalConnector c = new TerminalConnector(new SimpleFactory(new ConnectorMock()), "xID", "xName", false); + assertFalse(c.isInitialized()); + c.getId(); + assertFalse(c.isInitialized()); + c.getName(); + assertFalse(c.isInitialized()); + c.isHidden(); + assertFalse(c.isInitialized()); + c.getSettingsSummary(); + assertFalse(c.isInitialized()); + c.setTerminalSize(10, 10); + assertFalse(c.isInitialized()); + c.load(null); + assertFalse(c.isInitialized()); + c.save(null); + assertFalse(c.isInitialized()); + c.getAdapter(ConnectorMock.class); + assertFalse(c.isInitialized()); + } + + public void testGetAdapter() { + if (!Platform.isRunning()) + return; + ConnectorMock mock = new ConnectorMock(); + TerminalConnector c = new TerminalConnector(new SimpleFactory(mock), "xID", "xName", false); + assertNull(c.getAdapter(ConnectorMock.class)); + // the load is called after the connect... + c.connect(new TerminalControlMock()); + + assertSame(mock, c.getAdapter(ConnectorMock.class)); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java new file mode 100644 index 00000000000..c44d936135a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalConnectorTest.java @@ -0,0 +1,242 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + * Martin Oberhuber (Wind River) - [204796] Terminal should allow setting the encoding to use + * Uwe Stieber (Wind River) - [282996] [terminal][api] Add "hidden" attribute to terminal connector extension point + * Anton Leherbauer (Wind River) - [433751] Add option to enable VT100 line wrapping mode + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.connector; + +import java.io.OutputStream; + +import junit.framework.TestCase; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.internal.terminal.connector.TerminalConnector.Factory; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +public class TerminalConnectorTest extends TestCase { + public class SettingsMock implements ISettingsStore { + + public String get(String key) { + return null; + } + + public String get(String key, String defaultValue) { + return null; + } + + public void put(String key, String value) { + } + + } + public static class TerminalControlMock implements ITerminalControl { + + public void setEncoding(String encoding) { + } + + public String getEncoding() { + return "ISO-8859-1"; //$NON-NLS-1$ + } + + public void displayTextInTerminal(String text) { + } + + public OutputStream getRemoteToTerminalOutputStream() { + return null; + } + + public Shell getShell() { + return null; + } + + public TerminalState getState() { + return null; + } + + public void setMsg(String msg) { + } + + public void setState(TerminalState state) { + } + + public void setTerminalTitle(String title) { + } + + public void setupTerminal(Composite parent) { + } + + public boolean isConnectOnEnterIfClosed() { + return false; + } + + public void setConnectOnEnterIfClosed(boolean on) { + } + + public void setVT100LineWrapping(boolean enable) { + } + + public boolean isVT100LineWrapping() { + return false; + } + } + static class ConnectorMock extends TerminalConnectorImpl { + + public boolean fEcho; + public int fWidth; + public int fHeight; + public ITerminalControl fTerminalControl; + public ISettingsStore fSaveStore; + public ISettingsStore fLoadStore; + public boolean fDisconnect; + + public boolean isLocalEcho() { + return fEcho; + } + public void setTerminalSize(int newWidth, int newHeight) { + fWidth=newWidth; + fHeight=newHeight; + } + public void connect(ITerminalControl control) { + super.connect(control); + fTerminalControl = control; + } + public void doDisconnect() { + fDisconnect=true; + } + + public OutputStream getTerminalToRemoteStream() { + return null; + } + + public String getSettingsSummary() { + return "Summary"; + } + + public void load(ISettingsStore store) { + fLoadStore=store; + } + + public void save(ISettingsStore store) { + fSaveStore=store; + } + } + static class SimpleFactory implements Factory { + final TerminalConnectorImpl fConnector; + public SimpleFactory(TerminalConnectorImpl connector) { + fConnector = connector; + } + public TerminalConnectorImpl makeConnector() throws Exception { + // TODO Auto-generated method stub + return fConnector; + } + } + public void testGetInitializationErrorMessage() { + TerminalConnector c=new TerminalConnector(new SimpleFactory(new ConnectorMock()),"xID","xName", false); + c.connect(new TerminalControlMock()); + assertNull(c.getInitializationErrorMessage()); + + c=new TerminalConnector(new SimpleFactory(new ConnectorMock(){ + public void initialize() throws Exception { + throw new Exception("FAILED"); + }}),"xID","xName", false); + c.connect(new TerminalControlMock()); + assertEquals("FAILED",c.getInitializationErrorMessage()); + + } + + public void testGetIdAndName() { + TerminalConnector c=new TerminalConnector(new SimpleFactory(new ConnectorMock()),"xID","xName", false); + assertEquals("xID", c.getId()); + assertEquals("xName", c.getName()); + } + + public void testConnect() { + TerminalConnector c=new TerminalConnector(new SimpleFactory(new ConnectorMock()),"xID","xName", false); + assertFalse(c.isInitialized()); + c.connect(new TerminalControlMock()); + assertTrue(c.isInitialized()); + + } + + public void testDisconnect() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + TerminalControlMock control=new TerminalControlMock(); + c.connect(control); + c.disconnect(); + assertTrue(mock.fDisconnect); + } + + public void testGetTerminalToRemoteStream() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + TerminalControlMock control=new TerminalControlMock(); + c.connect(control); + assertSame(mock.fTerminalControl,control); + } + + public void testGetSettingsSummary() { + TerminalConnector c=new TerminalConnector(new SimpleFactory(new ConnectorMock()),"xID","xName", false); + assertEquals("Not Initialized", c.getSettingsSummary()); + c.connect(new TerminalControlMock()); + assertEquals("Summary", c.getSettingsSummary()); + } + + public void testIsLocalEcho() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + assertFalse(c.isLocalEcho()); + mock.fEcho=true; + assertTrue(c.isLocalEcho()); + } + + public void testLoad() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + ISettingsStore s=new SettingsMock(); + c.load(s); + // the load is called after the connect... + assertNull(mock.fLoadStore); + c.connect(new TerminalControlMock()); + assertSame(s,mock.fLoadStore); + } + + public void testSave() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + ISettingsStore s=new SettingsMock(); + c.save(s); + assertNull(mock.fSaveStore); + c.connect(new TerminalControlMock()); + c.save(s); + assertSame(s,mock.fSaveStore); + } + + public void testSetDefaultSettings() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + c.setDefaultSettings(); + } + + public void testSetTerminalSize() { + ConnectorMock mock=new ConnectorMock(); + TerminalConnector c=new TerminalConnector(new SimpleFactory(mock),"xID","xName", false); + c.setTerminalSize(100, 200); + + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalToRemoteInjectionOutputStreamTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalToRemoteInjectionOutputStreamTest.java new file mode 100644 index 00000000000..da374dee490 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/connector/TerminalToRemoteInjectionOutputStreamTest.java @@ -0,0 +1,177 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.connector; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; + +import junit.framework.TestCase; + +public class TerminalToRemoteInjectionOutputStreamTest extends TestCase { + final static String ENCODING="UTF-8"; + /** + * This class escapes strings coming on the original + * terminal.. + * + */ + class CleverInterceptor extends TerminalToRemoteInjectionOutputStream.Interceptor { + + public void close() throws IOException { + } + public void write(int b) throws IOException { + fOriginal.write('['); + fOriginal.write(b); + fOriginal.write(']'); + } + public void write(byte[] b, int off, int len) throws IOException { + fOriginal.write('['); + fOriginal.write(b,off,len); + fOriginal.write(']'); + } + + } + class NullInterceptor extends TerminalToRemoteInjectionOutputStream.Interceptor { + } + public void testClose() throws UnsupportedEncodingException, IOException { + ByteArrayOutputStream bs=new ByteArrayOutputStream(); + TerminalToRemoteInjectionOutputStream s= new TerminalToRemoteInjectionOutputStream(bs); + s.write("begin:".getBytes(ENCODING)); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + OutputStream os1=s.grabOutput(); + os1.write('x'); + s.write('A'); + os1.write('y'); + s.write('B'); + os1.close(); + + s.write('-'); + OutputStream os=s.grabOutput(); + // make sure the closed output does not inject anything + try { + os1.write('k'); + fail("..."); + } catch (Exception e) { + } + os.write('X'); + s.write('a'); + os.write('Y'); + // make sure the closed output does not inject anything + try { + os1.write('l'); + fail("..."); + } catch (Exception e) { + } + s.write('b'); + os.close(); + assertEquals("begin:xyAB-XYab", new String(bs.toByteArray(),ENCODING)); + } + + public void testFlush() { + } + + public void testWriteInt() throws UnsupportedEncodingException, IOException { + ByteArrayOutputStream bs=new ByteArrayOutputStream(); + TerminalToRemoteInjectionOutputStream s= new TerminalToRemoteInjectionOutputStream(bs); + s.write("begin:".getBytes(ENCODING)); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + OutputStream os=s.grabOutput(); + os.write('x'); + s.write('A'); + os.write('y'); + s.write('B'); + s.close(); + assertEquals("begin:xyAB", new String(bs.toByteArray(),ENCODING)); + + } + + public void testWriteByteArray() { + } + + public void testWriteByteArrayIntInt() { + } + public void testGrabOutput() throws UnsupportedEncodingException, IOException { + ByteArrayOutputStream bs=new ByteArrayOutputStream(); + TerminalToRemoteInjectionOutputStream s= new TerminalToRemoteInjectionOutputStream(bs); + s.write("begin:".getBytes(ENCODING)); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + OutputStream os1=s.grabOutput(); + OutputStream os2; + try { + os2=s.grabOutput(); + fail("should fail until the foirst output is closed"); + } catch (IOException e) { + } + os1.close(); + os2=s.grabOutput(); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + os2.write("Test".getBytes(ENCODING)); + assertEquals("begin:Test", new String(bs.toByteArray(),ENCODING)); + s.write(" west".getBytes(ENCODING)); + assertEquals("begin:Test", new String(bs.toByteArray(),ENCODING)); + os2.write(" the".getBytes(ENCODING)); + assertEquals("begin:Test the", new String(bs.toByteArray(),ENCODING)); + os2.close(); + assertEquals("begin:Test the west", new String(bs.toByteArray(),ENCODING)); + s.write('!'); + assertEquals("begin:Test the west!", new String(bs.toByteArray(),ENCODING)); + + } + public void testGrabOutputWithCleverInterceptor() throws UnsupportedEncodingException, IOException { + ByteArrayOutputStream bs=new ByteArrayOutputStream(); + TerminalToRemoteInjectionOutputStream s= new TerminalToRemoteInjectionOutputStream(bs); + s.write("begin:".getBytes(ENCODING)); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + // the injector escapes the output coming from the main stream + OutputStream os=s.grabOutput(new CleverInterceptor()); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + os.write("Test".getBytes(ENCODING)); + assertEquals("begin:Test", new String(bs.toByteArray(),ENCODING)); + s.write(" west".getBytes(ENCODING)); + assertEquals("begin:Test[ west]", new String(bs.toByteArray(),ENCODING)); + os.write(" the".getBytes(ENCODING)); + assertEquals("begin:Test[ west] the", new String(bs.toByteArray(),ENCODING)); + s.write('x'); + assertEquals("begin:Test[ west] the[x]", new String(bs.toByteArray(),ENCODING)); + os.close(); + assertEquals("begin:Test[ west] the[x]", new String(bs.toByteArray(),ENCODING)); + s.write('!'); + assertEquals("begin:Test[ west] the[x]!", new String(bs.toByteArray(),ENCODING)); + + } + public void testGrabOutputWithNullInterceptor() throws UnsupportedEncodingException, IOException { + ByteArrayOutputStream bs=new ByteArrayOutputStream(); + TerminalToRemoteInjectionOutputStream s= new TerminalToRemoteInjectionOutputStream(bs); + s.write("begin:".getBytes(ENCODING)); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + // bytes written to the main stream are ignored while the injector + // is active + OutputStream os=s.grabOutput(new NullInterceptor()); + assertEquals("begin:", new String(bs.toByteArray(),ENCODING)); + os.write("Test".getBytes(ENCODING)); + assertEquals("begin:Test", new String(bs.toByteArray(),ENCODING)); + s.write(" west".getBytes(ENCODING)); + assertEquals("begin:Test", new String(bs.toByteArray(),ENCODING)); + os.write(" the".getBytes(ENCODING)); + assertEquals("begin:Test the", new String(bs.toByteArray(),ENCODING)); + s.write('x'); + assertEquals("begin:Test the", new String(bs.toByteArray(),ENCODING)); + os.close(); + assertEquals("begin:Test the", new String(bs.toByteArray(),ENCODING)); + s.write('!'); + assertEquals("begin:Test the!", new String(bs.toByteArray(),ENCODING)); + + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/AllTests.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/AllTests.java new file mode 100644 index 00000000000..11b6b283f3b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/AllTests.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Terminal emulator test cases. + * Runs in emulator package to allow access to default visible items. + */ +public class AllTests extends TestCase { + public AllTests() { + super(null); + } + + public AllTests(String name) { + super(name); + } + + public static Test suite() { + TestSuite suite = new TestSuite(AllTests.class.getName()); + suite.addTestSuite(VT100EmulatorBackendTest.class); + return suite; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java new file mode 100644 index 00000000000..e90adb7f22b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/emulator/VT100EmulatorBackendTest.java @@ -0,0 +1,1383 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [168197] Fix Terminal for CDC-1.1/Foundation-1.1 + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + * Anton Leherbauer (Wind River) - [458218] Add support for ANSI insert mode + * Anton Leherbauer (Wind River) - [458402] Add support for scroll up/down and scroll region + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.emulator; + +import junit.framework.TestCase; + +import org.eclipse.tm.internal.terminal.model.TerminalTextDataStore; +import org.eclipse.tm.internal.terminal.model.TerminalTextTestHelper; +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; +import org.eclipse.tm.terminal.model.Style; + +public class VT100EmulatorBackendTest extends TestCase { + + protected IVT100EmulatorBackend makeBakend(ITerminalTextData term) { + return new VT100EmulatorBackend(term); + } + + protected ITerminalTextData makeITerminalTextData() { + return new TerminalTextDataStore(); + } + + protected String toSimple(ITerminalTextData term) { + return TerminalTextTestHelper.toSimple(term); + } + protected String toMultiLineText(ITerminalTextDataReadOnly term) { + return TerminalTextTestHelper.toMultiLineText(term); + } + + protected void fill(ITerminalTextData term, String s) { + TerminalTextTestHelper.fill(term,s); + } + + protected void fillSimple(ITerminalTextData term, String s) { + TerminalTextTestHelper.fillSimple(term, s); + } + + + /** + * Used for multi line text + * @param expected + * @param actual + */ + protected void assertEqualsTerm(String expected,String actual) { + assertEquals(expected.replace(' ', '.'), actual.replace('\000', '.')); + } + /** + * Used for simple text + * @param expected + * @param actual + */ + protected void assertEqualsSimple(String expected,String actual) { + assertEquals(-1,actual.indexOf('\n')); + assertEquals(expected, actual); + } + public void testClearAll() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + vt100.setDimensions(3, 4); + fill(term, "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555"); + vt100.clearAll(); + assertEqualsTerm( + " \n" + + " \n" + + " ",toMultiLineText(term)); + } + public void testSetDimensions() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + String s = "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555"; + fill(term, s); + vt100.setDimensions(3, 4); + assertEquals(3,vt100.getLines()); + assertEquals(4,vt100.getColumns()); + assertEqualsTerm(s,toMultiLineText(term)); + + vt100.setCursor(0, 2); + vt100.setDimensions(2, 4); + assertEquals(0, vt100.getCursorLine()); + assertEquals(2, vt100.getCursorColumn()); + + vt100.setCursor(0, 2); + vt100.setDimensions(5, 4); + assertEquals(3, vt100.getCursorLine()); + assertEquals(2, vt100.getCursorColumn()); + + assertEqualsTerm(s,toMultiLineText(term)); + + vt100.setCursor(0, 3); + vt100.setDimensions(5, 2); + assertEquals(0, vt100.getCursorLine()); + assertEquals(1, vt100.getCursorColumn()); + } + + public void testToAbsoluteLine() { + ITerminalTextData term=makeITerminalTextData(); + VT100EmulatorBackend vt100=new VT100EmulatorBackend(term); + vt100.setDimensions(2, 3); + assertEquals(vt100.toAbsoluteLine(0),0); + // TODO + term=makeITerminalTextData(); + vt100=new VT100EmulatorBackend(term); + vt100.setDimensions(1, 10); + assertEquals(vt100.toAbsoluteLine(0),0); + } + + public void testInsertCharacters() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + vt100.setDimensions(3, 4); + String s = + "aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "1234\n" + + "4567\n" + + "9012"; + fill(term, s); + vt100.setCursor(0, 0); + vt100.insertCharacters(1); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " 123\n" + + "4567\n" + + "9012",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 1); + vt100.insertCharacters(1); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "1234\n" + + "4 56\n" + + "9012",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 1); + vt100.insertCharacters(2); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "1234\n" + + "4 5\n" + + "9012",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 0); + vt100.insertCharacters(10); + assertEqualsTerm(" ",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 0); + vt100.insertCharacters(14); + assertEqualsTerm(" ",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 3); + vt100.insertCharacters(14); + assertEqualsTerm("012 ",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 3); + vt100.insertCharacters(0); + assertEqualsTerm("0123456789",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 3); + vt100.insertCharacters(2); + assertEqualsTerm("012 34567",toMultiLineText(term)); + } + + public void testEraseToEndOfScreen() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + vt100.setDimensions(3, 4); + String s = + "aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "4567\n" + + "8901"; + fill(term, s); + vt100.setCursor(0, 0); + vt100.eraseToEndOfScreen(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " \n" + + " ",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 0); + vt100.eraseToEndOfScreen(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + " \n" + + " ",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 1); + vt100.eraseToEndOfScreen(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(1,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "4 \n" + + " ",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 4); + assertEquals(1,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + vt100.eraseToEndOfScreen(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "456.\n" + + " ",toMultiLineText(term)); + + + fill(term, s); + vt100.setCursor(1, 5); + vt100.eraseToEndOfScreen(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "456.\n" + + " ",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(2, 3); + vt100.eraseToEndOfScreen(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "4567\n" + + "890 ",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(2, 5); + vt100.eraseToEndOfScreen(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "4567\n" + + "890.",toMultiLineText(term)); + } + + public void testEraseToCursor() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + vt100.setDimensions(3, 4); + String s = + "aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "0123\n" + + "4567\n" + + "8901"; + fill(term, s); + vt100.setCursor(0, 0); + vt100.eraseToCursor(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " 123\n" + + "4567\n" + + "8901",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 0); + vt100.eraseToCursor(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " 567\n" + + "8901",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 1); + vt100.eraseToCursor(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(1,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " 67\n" + + "8901",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 4); + vt100.eraseToCursor(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " \n" + + "8901",toMultiLineText(term)); + + + fill(term, s); + vt100.setCursor(1, 5); + vt100.eraseToCursor(); + assertEquals(1,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " \n" + + "8901",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(2, 3); + vt100.eraseToCursor(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " \n" + + " ",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(2, 5); + vt100.eraseToCursor(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + " \n" + + " \n" + + " ",toMultiLineText(term)); + } + + public void testEraseAll() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + vt100.setDimensions(3, 4); + fill(term, "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555"); + vt100.eraseAll(); + assertEqualsTerm("0000\n" + + "1111\n" + + "2222\n" + + " \n" + + " \n" + + " ",toMultiLineText(term)); + } + + public void testEraseLine() { + String s = + "abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + "EFGHI"; + + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(0, 3); + vt100.eraseLine(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + " \n" + + "zABCD\n" + + "EFGHI", toMultiLineText(term)); + + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(2, 3); + vt100.eraseLine(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + " ", toMultiLineText(term)); + } + + public void testEraseLineToEnd() { + String s = + "abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + "EFGHI"; + + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(0, 3); + vt100.eraseLineToEnd(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvw \n" + + "zABCD\n" + + "EFGHI", toMultiLineText(term)); + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(0, 0); + vt100.eraseLineToEnd(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + " \n" + + "zABCD\n" + + "EFGHI", toMultiLineText(term)); + + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(2, 3); + vt100.eraseLineToEnd(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + "EFG ", toMultiLineText(term)); + vt100.setDimensions(3, 5); + fill(term, s); + + vt100.setCursor(2, 4); + vt100.eraseLineToEnd(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(4,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + "EFGH ", toMultiLineText(term)); + + vt100.setCursor(2, 5); + vt100.eraseLineToEnd(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(4,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + "EFGH ", toMultiLineText(term)); + + } + + public void testEraseLineToCursor() { + String s = + "abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + "EFGHI"; + + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(0, 3); + vt100.eraseLineToCursor(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + " y\n" + + "zABCD\n" + + "EFGHI", toMultiLineText(term)); + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(0, 0); + vt100.eraseLineToCursor(); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + " vwxy\n" + + "zABCD\n" + + "EFGHI", toMultiLineText(term)); + + + vt100.setDimensions(3, 5); + fill(term, s); + vt100.setCursor(2, 3); + vt100.eraseLineToCursor(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + " I", toMultiLineText(term)); + vt100.setDimensions(3, 5); + fill(term, s); + + vt100.setCursor(2, 4); + vt100.eraseLineToCursor(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(4,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + " ", toMultiLineText(term)); + + vt100.setCursor(2, 5); + vt100.eraseLineToCursor(); + assertEquals(2,vt100.getCursorLine()); + assertEquals(4,vt100.getCursorColumn()); + assertEqualsTerm("abcde\n" + + "fghij\n" + + "klmno\n" + + "pqrst\n" + + "uvwxy\n" + + "zABCD\n" + + " ", toMultiLineText(term)); + + } + + public void testInsertLines() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + String s = "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555"; + vt100.setDimensions(3, 4); + fill(term, s); + vt100.setCursor(0, 0); + vt100.insertLines(1); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + " \n" + + "3333\n" + + "4444", toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 0); + vt100.insertLines(1); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + " \n" + + "4444", toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 0); + vt100.insertLines(2); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + " \n" + + " ", toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 3); + vt100.insertLines(2); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + " \n" + + " ", toMultiLineText(term)); + + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(1, 3); + vt100.insertLines(2); + assertEqualsTerm( + "0000\n" + + " \n" + + " \n" + + "1111\n" + + "2222\n" + + "3333", toMultiLineText(term)); + + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(1, 3); + vt100.insertLines(7); + assertEqualsTerm( + "0000\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ", toMultiLineText(term)); + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(0, 0); + vt100.insertLines(7); + assertEqualsTerm( + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ", toMultiLineText(term)); + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(0, 0); + vt100.insertLines(5); + assertEqualsTerm( + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "0000", toMultiLineText(term)); + } + + public void testDeleteCharacters() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + vt100.setDimensions(3, 4); + String s = + "aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "1234\n" + + "4567\n" + + "9012"; + fill(term, s); + vt100.setCursor(0, 0); + vt100.deleteCharacters(1); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "234 \n" + + "4567\n" + + "9012",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 1); + vt100.deleteCharacters(1); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "1234\n" + + "467 \n" + + "9012",toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 1); + vt100.deleteCharacters(2); + assertEqualsTerm("aaaa\n" + + "bbbb\n" + + "cccc\n" + + "dddd\n" + + "eeee\n" + + "ffff\n" + + "1234\n" + + "47 \n" + + "9012",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 0); + vt100.deleteCharacters(10); + assertEqualsTerm(" ",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 0); + vt100.deleteCharacters(14); + assertEqualsTerm(" ",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 3); + vt100.deleteCharacters(0); + assertEqualsTerm("0123456789",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 3); + vt100.deleteCharacters(2); + assertEqualsTerm("01256789 ",toMultiLineText(term)); + + vt100.setDimensions(1, 10); + fill(term, "0123456789"); + vt100.setCursor(0, 3); + vt100.deleteCharacters(14); + assertEqualsTerm("012 ",toMultiLineText(term)); + + } + + public void testDeleteLines() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + String s = "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555"; + vt100.setDimensions(3, 4); + fill(term, s); + vt100.setCursor(0, 0); + vt100.deleteLines(1); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "4444\n" + + "5555\n" + + " ", toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 0); + vt100.deleteLines(1); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "5555\n" + + " ", toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 0); + vt100.deleteLines(2); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + " \n" + + " ", toMultiLineText(term)); + + fill(term, s); + vt100.setCursor(1, 3); + vt100.deleteLines(2); + assertEqualsTerm( + "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + " \n" + + " ", toMultiLineText(term)); + + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(1, 3); + vt100.deleteLines(2); + assertEqualsTerm( + "0000\n" + + "3333\n" + + "4444\n" + + "5555\n" + + " \n" + + " ", toMultiLineText(term)); + + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(1, 3); + vt100.deleteLines(7); + assertEqualsTerm( + "0000\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ", toMultiLineText(term)); + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(0, 0); + vt100.deleteLines(7); + assertEqualsTerm( + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ", toMultiLineText(term)); + + vt100.setDimensions(6, 4); + fill(term, s); + vt100.setCursor(0, 0); + vt100.deleteLines(5); + assertEqualsTerm( + "5555\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " ", toMultiLineText(term)); + } + + public void testGetDefaultStyle() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + Style style=Style.getStyle("white", "black"); + vt100.setDefaultStyle(style); + assertSame(style, vt100.getDefaultStyle()); + Style style2=style.setBold(true); + vt100.setDefaultStyle(style2); + assertSame(style2, vt100.getDefaultStyle()); + } + + public void testGetStyle() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + Style style=Style.getStyle("white", "black"); + vt100.setStyle(style); + assertSame(style, vt100.getStyle()); + Style style2=style.setBold(true); + vt100.setStyle(style2); + assertSame(style2, vt100.getStyle()); + } + + public void testAppendString() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(6); + vt100.setDimensions(3, 4); + vt100.setCursor(0, 0); + assertEqualsTerm( + " \n" + + " \n" + + " ", toMultiLineText(term)); + vt100.appendString("012"); + assertEqualsTerm( + "012 \n" + + " \n" + + " ", toMultiLineText(term)); + assertEquals(0,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + vt100.appendString("3"); + assertEqualsTerm( + "0123\n" + + " \n" + + " ", toMultiLineText(term)); + assertEquals(1,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + + vt100.appendString("567890"); + assertEqualsTerm( + "0123\n" + + "5678\n" + + "90 ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + + + vt100.appendString("a"); + assertEqualsTerm( + "0123\n" + + "5678\n" + + "90a ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + + vt100.appendString("b"); + assertEqualsTerm( + "0123\n" + + "5678\n" + + "90ab\n" + + " ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + + vt100.appendString("cd"); + assertEqualsTerm( + "0123\n" + + "5678\n" + + "90ab\n" + + "cd ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + + vt100.appendString("efgh"); + assertEqualsTerm( + "0123\n" + + "5678\n" + + "90ab\n" + + "cdef\n" + + "gh ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + + vt100.appendString("ijklmnopqrstuvwx"); + assertEqualsTerm( + "cdef\n" + + "ghij\n" + + "klmn\n" + + "opqr\n" + + "stuv\n" + + "wx ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + + vt100.setCursor(1, 1); + vt100.appendString("123"); + assertEqualsTerm( + "cdef\n" + + "ghij\n" + + "klmn\n" + + "opqr\n" + + "s123\n" + + "wx ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + + vt100.setCursor(1, 1); + vt100.appendString("ABCDEFGHIJKL"); + assertEqualsTerm( + "klmn\n" + + "opqr\n" + + "sABC\n" + + "DEFG\n" + + "HIJK\n" + + "L ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(1,vt100.getCursorColumn()); + + } + + public void testProcessNewline() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + String s = "0000\n" + + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555"; + term.setMaxHeight(6); + vt100.setDimensions(3, 4); + vt100.setCursor(0, 0); + fill(term,s); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.processNewline(); + assertEqualsTerm(s, toMultiLineText(term)); + assertEquals(1,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursorColumn(3); + vt100.processNewline(); + assertEqualsTerm(s, toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + + vt100.processNewline(); + assertEqualsTerm( + "1111\n" + + "2222\n" + + "3333\n" + + "4444\n" + + "5555\n" + + " ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + + + vt100.processNewline(); + assertEqualsTerm( + "2222\n" + + "3333\n" + + "4444\n" + + "5555\n" + + " \n" + + " ", toMultiLineText(term)); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + } + + public void testSetCursorLine() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(6); + vt100.setDimensions(3, 4); + // the cursor still at the beginning.... + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(0, 2); + vt100.setCursorLine(1); + assertEquals(1,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + vt100.setCursor(0, -2); + vt100.setCursorLine(-1); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(0, 10); + vt100.setCursorLine(10); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + } + public void testSetCursorAndSetDimensions() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(3, 4); + // the cursor still at the beginning.... + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setDimensions(6, 4); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(2, 3); + vt100.setDimensions(8, 4); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + } + + public void testSetCursorColumn() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(6); + vt100.setDimensions(3, 4); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(1, 0); + vt100.setCursorColumn(2); + assertEquals(1,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + vt100.setCursor(-1, -2); + vt100.setCursorColumn(-2); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(10, 0); + vt100.setCursorColumn(10); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + } + + public void testSetCursor() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(6); + vt100.setDimensions(3, 4); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(0, 0); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(1, 2); + assertEquals(1,vt100.getCursorLine()); + assertEquals(2,vt100.getCursorColumn()); + vt100.setCursor(-1, -2); + assertEquals(0,vt100.getCursorLine()); + assertEquals(0,vt100.getCursorColumn()); + vt100.setCursor(10, 10); + assertEquals(2,vt100.getCursorLine()); + assertEquals(3,vt100.getCursorColumn()); + } + + public void testVT100LineWrappingOn() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(6, 4); + vt100.setVT100LineWrapping(true); + vt100.appendString("abcd"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("1234"); + vt100.setCursorColumn(0); + vt100.processNewline(); + assertEquals(2, vt100.getCursorLine()); + } + + public void testVT100LineWrappingOff() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(6, 4); + vt100.setVT100LineWrapping(false); + vt100.appendString("abcd"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("1234"); + vt100.setCursorColumn(0); + vt100.processNewline(); + assertEquals(4, vt100.getCursorLine()); + } + + public void testWrappedLines() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(6, 4); + vt100.setVT100LineWrapping(true); + vt100.appendString("abcd123"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("abc"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("1234abcd"); + assertEquals(4, vt100.getCursorLine()); + assertTrue(term.isWrappedLine(0)); + assertFalse(term.isWrappedLine(1)); + assertFalse(term.isWrappedLine(2)); + assertTrue(term.isWrappedLine(3)); + } + + public void testInsertMode() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(4, 6); + // replace mode + vt100.appendString("123"); + vt100.setCursorColumn(0); + vt100.appendString("abc"); + assertEquals("abc", new String(term.getChars(0))); + vt100.clearAll(); + // insert mode + vt100.setCursorColumn(0); + vt100.appendString("123"); + vt100.setCursorColumn(0); + vt100.setInsertMode(true); + vt100.appendString("abc"); + vt100.setInsertMode(false); + assertEquals("abc123", new String(term.getChars(0))); + } + + public void testScrollRegion() { + ITerminalTextData term=makeITerminalTextData(); + IVT100EmulatorBackend vt100=makeBakend(term); + term.setMaxHeight(10); + vt100.setDimensions(8, 6); + vt100.appendString("123"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("456"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("789"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("abc"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("def"); + vt100.setCursorColumn(0); + vt100.processNewline(); + vt100.appendString("ghi"); + + // test scroll within region + vt100.setCursorLine(1); + vt100.setScrollRegion(1, 4); + vt100.scrollUp(1); + assertEquals("123", new String(term.getChars(0))); + assertEquals("789", new String(term.getChars(1))); + assertEquals("abc", new String(term.getChars(2))); + assertEquals("def", new String(term.getChars(3))); + assertNull(term.getChars(4)); + assertEquals("ghi", new String(term.getChars(5))); + vt100.scrollDown(1); + assertEquals("123", new String(term.getChars(0))); + assertNull(term.getChars(1)); + assertEquals("789", new String(term.getChars(2))); + assertEquals("abc", new String(term.getChars(3))); + assertEquals("def", new String(term.getChars(4))); + assertEquals("ghi", new String(term.getChars(5))); + + // test scroll without region + vt100.setScrollRegion(-1, -1); + vt100.scrollDown(1); + assertNull(term.getChars(0)); + assertEquals("123", new String(term.getChars(1))); + assertNull(term.getChars(2)); + assertEquals("789", new String(term.getChars(3))); + assertEquals("abc", new String(term.getChars(4))); + assertEquals("def", new String(term.getChars(5))); + assertEquals("ghi", new String(term.getChars(6))); + vt100.scrollUp(1); + assertEquals("123", new String(term.getChars(0))); + assertNull(term.getChars(1)); + assertEquals("789", new String(term.getChars(2))); + assertEquals("abc", new String(term.getChars(3))); + assertEquals("def", new String(term.getChars(4))); + assertEquals("ghi", new String(term.getChars(5))); + + // test scroll by newline + vt100.setScrollRegion(1, 4); + vt100.setCursorLine(4); + vt100.processNewline(); + assertEquals("123", new String(term.getChars(0))); + assertEquals("789", new String(term.getChars(1))); + assertEquals("abc", new String(term.getChars(2))); + assertEquals("def", new String(term.getChars(3))); + assertNull(term.getChars(4)); + assertEquals("ghi", new String(term.getChars(5))); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/AbstractITerminalTextDataTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/AbstractITerminalTextDataTest.java new file mode 100644 index 00000000000..6d2cc23d09b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/AbstractITerminalTextDataTest.java @@ -0,0 +1,832 @@ +/******************************************************************************* + * Copyright (c) 2007-2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Anton Leherbauer (Wind River) - [453393] Add support for copying wrapped lines without line break + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; +import junit.framework.TestCase; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; +import org.eclipse.tm.terminal.model.LineSegment; +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +abstract public class AbstractITerminalTextDataTest extends TestCase { + abstract protected ITerminalTextData makeITerminalTextData(); + + protected void setUp() throws Exception { + try { + assert false; + throw new Error("No Assertions! Run this code with assertions enabled! (vmargs: -ea)"); + } catch(AssertionError e) { + // OK, assertions are enabled! + } + super.setUp(); + } + protected String toSimple(ITerminalTextData term) { + return TerminalTextTestHelper.toSimple(term); + } + protected String toMultiLineText(ITerminalTextDataReadOnly term) { + return TerminalTextTestHelper.toMultiLineText(term); + } + + protected void fill(ITerminalTextData term, String s) { + TerminalTextTestHelper.fill(term,s); + } + + protected void fill(ITerminalTextData term, int i, int j, String s) { + TerminalTextTestHelper.fill(term,i,j,s); + } + + protected void fillSimple(ITerminalTextData term, String s) { + TerminalTextTestHelper.fillSimple(term, s); + } + + + /** + * Used for multi line text + * @param expected + * @param actual + */ + protected void assertEqualsTerm(String expected,String actual) { + assertEquals(expected, actual); + } + /** + * Used for simple text + * @param expected + * @param actual + */ + protected void assertEqualsSimple(String expected,String actual) { + assertEquals(-1,actual.indexOf('\n')); + assertEquals(expected, actual); + } + public void testGetWidth() { + ITerminalTextData term=makeITerminalTextData(); + assertEquals(0, term.getWidth()); + term.setDimensions(term.getHeight(), 10); + assertEquals(10, term.getWidth()); + term.setDimensions(term.getHeight(), 0); + assertEquals(0, term.getWidth()); + } + + public void testAddLine() { + String s= + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555"; + ITerminalTextData term=makeITerminalTextData(); + fill(term, s); + term.setMaxHeight(5); + term.addLine(); + assertEqualsTerm( + "222\n" + + "333\n" + + "444\n" + + "555\n" + + "\000\000\000", toMultiLineText(term)); + } + public void testCleanLine() { + String s= + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555"; + ITerminalTextData term=makeITerminalTextData(); + fill(term, s); + term.cleanLine(0); + assertEqualsTerm( + "\000\000\000\n" + + "222\n" + + "333\n" + + "444\n" + + "555", toMultiLineText(term)); + + fill(term, s); + term.cleanLine(4); + assertEqualsTerm( + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "\000\000\000", toMultiLineText(term)); + } + + public void testMaxSize() { + String s= + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555"; + ITerminalTextData term=makeITerminalTextData(); + term.setMaxHeight(8); + fill(term, s); + assertEquals(5, term.getHeight()); + assertEquals(8, term.getMaxHeight()); + term.addLine(); + assertEquals(6, term.getHeight()); + assertEqualsTerm( + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555\n" + + "\000\000\000", toMultiLineText(term)); + term.addLine(); + assertEquals(7, term.getHeight()); + assertEqualsTerm( + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555\n" + + "\000\000\000\n" + + "\000\000\000", toMultiLineText(term)); + term.addLine(); + assertEquals(8, term.getHeight()); + assertEqualsTerm( + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555\n" + + "\000\000\000\n" + + "\000\000\000\n" + + "\000\000\000", toMultiLineText(term)); + term.addLine(); + assertEquals(8, term.getHeight()); + assertEqualsTerm( + "222\n" + + "333\n" + + "444\n" + + "555\n" + + "\000\000\000\n" + + "\000\000\000\n" + + "\000\000\000\n" + + "\000\000\000", toMultiLineText(term)); + term.addLine(); + assertEquals(8, term.getHeight()); + assertEqualsTerm( + "333\n" + + "444\n" + + "555\n" + + "\000\000\000\n" + + "\000\000\000\n" + + "\000\000\000\n" + + "\000\000\000\n" + + "\000\000\000", toMultiLineText(term)); + } + public void testGetHeight() { + ITerminalTextData term=makeITerminalTextData(); + assertEquals(0, term.getHeight()); + term.setDimensions(10, term.getWidth()); + assertEquals(10, term.getHeight()); + term.setDimensions(0, term.getWidth()); + assertEquals(0, term.getHeight()); + } + + public void testSetDimensions() { + ITerminalTextData term=makeITerminalTextData(); + assertEquals(0, term.getHeight()); + term.setDimensions(10, 5); + assertEquals(5, term.getWidth()); + assertEquals(10, term.getHeight()); + term.setDimensions(5, 10); + assertEquals(10, term.getWidth()); + assertEquals(5, term.getHeight()); + term.setDimensions(15, 0); + assertEquals(0, term.getWidth()); + assertEquals(15, term.getHeight()); + term.setDimensions(0, 12); + assertEquals(12, term.getWidth()); + assertEquals(0, term.getHeight()); + term.setDimensions(0, 0); + assertEquals(0, term.getWidth()); + assertEquals(0, term.getHeight()); + } + public void testResize() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(3, 5); + String s="12345\n" + + "abcde\n" + + "ABCDE"; + fill(term,0,0,s); + assertEqualsTerm(s, toMultiLineText(term)); + term.setDimensions(3, 4); + assertEqualsTerm( + "1234\n" + + "abcd\n" + + "ABCD", toMultiLineText(term)); + // the columns should be restored + term.setDimensions(3, 5); + assertEqualsTerm( + "12345\n" + + "abcde\n" + + "ABCDE", toMultiLineText(term)); + term.setDimensions(3, 6); + assertEqualsTerm( + "12345\000\n" + + "abcde\000\n" + + "ABCDE\000", toMultiLineText(term)); + term.setChar(0, 5, 'x', null); + term.setChar(1, 5, 'y', null); + term.setChar(2, 5, 'z', null); + assertEqualsTerm( + "12345x\n" + + "abcdey\n" + + "ABCDEz", toMultiLineText(term)); + term.setDimensions(2, 4); + assertEqualsTerm( + "1234\n" + + "abcd", toMultiLineText(term)); + } + + public void testResizeFailure() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(3, 5); + String s="12345\n" + + "abcde\n" + + "ABCDE"; + fill(term,0,0,s); + assertEqualsTerm(s, toMultiLineText(term)); + try { + term.setDimensions(-3, 4); + fail(); + } catch (RuntimeException e) { + // OK + } +// assertEquals(5, term.getWidth()); +// assertEquals(3, term.getHeight()); +// assertEquals(s, toSimpleText(term)); + } + + public void testGetLineSegments() { + Style s1=getDefaultStyle(); + Style s2=s1.setBold(true); + Style s3=s1.setUnderline(true); + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(8, 8); + LineSegment[] segments; + + term.setChars(0, 0,"0123".toCharArray(), s1); + term.setChars(0, 4,"abcd".toCharArray(), null); + segments=term.getLineSegments(0, 0, term.getWidth()); + assertEquals(2, segments.length); + assertSegment(0, "0123", s1, segments[0]); + assertSegment(4, "abcd", null, segments[1]); + + + segments=term.getLineSegments(0, 4, term.getWidth()-4); + assertEquals(1, segments.length); + assertSegment(4, "abcd", null, segments[0]); + + segments=term.getLineSegments(0, 3, 2); + assertEquals(2, segments.length); + assertSegment(3, "3", s1, segments[0]); + assertSegment(4, "a", null, segments[1]); + + segments=term.getLineSegments(0, 7, 1); + assertEquals(1, segments.length); + assertSegment(7, "d", null, segments[0]); + + segments=term.getLineSegments(0, 0, 1); + assertEquals(1, segments.length); + assertSegment(0, "0", s1, segments[0]); + + // line 1 + term.setChars(1, 0,"x".toCharArray(), s1); + term.setChars(1, 1,"y".toCharArray(), s2); + term.setChars(1, 2,"z".toCharArray(), s3); + + segments=term.getLineSegments(1, 0, term.getWidth()); + assertEquals(4, segments.length); + assertSegment(0, "x", s1, segments[0]); + assertSegment(1, "y", s2, segments[1]); + assertSegment(2, "z", s3, segments[2]); + assertSegment(3, "\000\000\000\000\000", null, segments[3]); + + // line 2 + term.setChars(2, 4,"klm".toCharArray(), s1); + segments=term.getLineSegments(2, 0, term.getWidth()); + assertEquals(3, segments.length); + assertSegment(0, "\000\000\000\000", null, segments[0]); + assertSegment(4, "klm", s1, segments[1]); + assertSegment(7, "\000", null, segments[2]); + + // line 3 + segments=term.getLineSegments(3, 0, term.getWidth()); + assertEquals(1, segments.length); + assertSegment(0, "\000\000\000\000\000\000\000\000", null, segments[0]); + + } + public void testGetLineSegmentsNull() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(8, 8); + LineSegment[] segments=term.getLineSegments(0, 0, term.getWidth()); + assertEquals(1, segments.length); + } + public void testGetLineSegmentsOutOfBounds() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(1, 8); + term.setChars(0,0,"xx".toCharArray(),null); + LineSegment[] segments=term.getLineSegments(0, 5, 2); + assertEquals(1, segments.length); + + + } + void assertSegment(int col,String text, Style style,LineSegment segment) { + assertEquals(col, segment.getColumn()); + assertEqualsTerm(text, segment.getText()); + assertEquals(style, segment.getStyle()); + + } + public void testGetChar() { + String s="12345\n" + + "abcde\n" + + "ABCDE"; + ITerminalTextData term=makeITerminalTextData(); + fill(term, s); + assertEquals('1', term.getChar(0,0)); + assertEquals('2', term.getChar(0,1)); + assertEquals('3', term.getChar(0,2)); + assertEquals('4', term.getChar(0,3)); + assertEquals('5', term.getChar(0,4)); + assertEquals('a', term.getChar(1,0)); + assertEquals('b', term.getChar(1,1)); + assertEquals('c', term.getChar(1,2)); + assertEquals('d', term.getChar(1,3)); + assertEquals('e', term.getChar(1,4)); + assertEquals('A', term.getChar(2,0)); + assertEquals('B', term.getChar(2,1)); + assertEquals('C', term.getChar(2,2)); + assertEquals('D', term.getChar(2,3)); + assertEquals('E', term.getChar(2,4)); + try { + term.getChar(0,-1); + fail(); + } catch (RuntimeException e) { + } + try { + term.getChar(-1,-1); + fail(); + } catch (RuntimeException e) { + } + try { + term.getChar(-1,0); + fail(); + } catch (RuntimeException e) { + } + try { + term.getChar(0,5); + fail(); + } catch (RuntimeException e) { + } + try { + term.getChar(3,5); + fail(); + } catch (RuntimeException e) { + } + try { + term.getChar(3,0); + fail(); + } catch (RuntimeException e) { + } + } + + public void testGetStyle() { + ITerminalTextData term=makeITerminalTextData(); + Style style=getDefaultStyle(); + term.setDimensions(6, 3); + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + char c=(char)('a'+column+line); + term.setChar(line, column, c, style.setForground(StyleColor.getStyleColor(""+c))); + } + } + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + char c=(char)('a'+column+line); + assertSame(style.setForground(StyleColor.getStyleColor(""+c)), term.getStyle(line, column)); + } + } + + } + + protected Style getDefaultStyle() { + return Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + } + + public void testSetChar() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(6, 3); + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + term.setChar(line, column, (char)('a'+column+line), null); + } + } + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + char c=(char)('a'+column+line); + assertEquals(c, term.getChar(line,column)); + } + } + assertEqualsTerm( + "abc\n" + + "bcd\n" + + "cde\n" + + "def\n" + + "efg\n" + + "fgh", toMultiLineText(term)); + } + public void testSetChars() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(6, 3); + for (int line = 0; line < term.getHeight(); line++) { + char[] chars=new char[term.getWidth()]; + for (int column = 0; column < term.getWidth(); column++) { + chars[column]=(char)('a'+column+line); + } + term.setChars(line, 0, chars, null); + } + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + char c=(char)('a'+column+line); + assertEquals(c, term.getChar(line,column)); + } + } + assertEqualsTerm( + "abc\n" + + "bcd\n" + + "cde\n" + + "def\n" + + "efg\n" + + "fgh", toMultiLineText(term)); + + term.setChars(3, 1, new char[]{'1','2'}, null); + assertEqualsTerm( + "abc\n" + + "bcd\n" + + "cde\n" + + "d12\n" + + "efg\n" + + "fgh", toMultiLineText(term)); + try { + // check if we cannot exceed the range + term.setChars(4, 1, new char[]{'1','2','3','4','5'}, null); + fail(); + } catch (RuntimeException e) {} + + } + public void testSetCharsLen() { + ITerminalTextData term=makeITerminalTextData(); + String s= "ZYXWVU\n" + + "abcdef\n" + + "ABCDEF"; + fill(term, s); + char[] chars=new char[]{'1','2','3','4','5','6','7','8'}; + term.setChars(1, 0, chars, 0, 6,null); + assertEqualsTerm( + "ZYXWVU\n" + + "123456\n" + + "ABCDEF", toMultiLineText(term)); + + fill(term, s); + term.setChars(1, 0, chars, 0, 5, null); + assertEqualsTerm("ZYXWVU\n" + + "12345f\n" + + "ABCDEF", toMultiLineText(term)); + + fill(term, s); + term.setChars(1, 0, chars, 1, 5, null); + assertEqualsTerm("ZYXWVU\n" + + "23456f\n" + + "ABCDEF", toMultiLineText(term)); + + fill(term, s); + term.setChars(1, 1, chars, 1, 4, null); + assertEqualsTerm("ZYXWVU\n" + + "a2345f\n" + + "ABCDEF", toMultiLineText(term)); + + + + fill(term, s); + term.setChars(1, 2, chars, 3, 4, null); + assertEqualsTerm("ZYXWVU\n" + + "ab4567\n" + + "ABCDEF", toMultiLineText(term)); + + fill(term, s); + try { + term.setChars(1, 0, chars, 7, 10, null); + fail(); + } catch (RuntimeException e) {} + fill(term, s); + try { + term.setChars(1, -1, chars, 0, 2, null); + fail(); + } catch (RuntimeException e) {} + try { + term.setChars(-1, 1, chars, 0, 2, null); + fail(); + } catch (RuntimeException e) {} + try { + term.setChars(1, 10, chars, 0, 2, null); + fail(); + } catch (RuntimeException e) {} + try { + term.setChars(10, 1, chars, 0, 2, null); + fail(); + } catch (RuntimeException e) {} +// assertEquals(s, toSimpleText(term)); + } + public void testSetCopyInto() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(3, 5); + String s="12345\n" + + "abcde\n" + + "ABCDE"; + fill(term,0,0,s); + ITerminalTextData termCopy=makeITerminalTextData(); + termCopy.copy(term); + assertEqualsTerm(s, toMultiLineText(termCopy)); + assertEqualsTerm(s, toMultiLineText(term)); + + termCopy.setChar(1, 1, 'X', null); + assertEqualsTerm(s, toMultiLineText(term)); + term.setDimensions(2, 4); + assertEquals(5, termCopy.getWidth()); + assertEquals(3, termCopy.getHeight()); + + assertEqualsTerm("12345\n" + + "aXcde\n" + + "ABCDE", toMultiLineText(termCopy)); + + assertEquals(4, term.getWidth()); + assertEquals(2, term.getHeight()); + } + public void testSetCopyLines() { + ITerminalTextData term=makeITerminalTextData(); + String s="012345"; + fillSimple(term, s); + ITerminalTextData termCopy=makeITerminalTextData(); + String sCopy="abcde"; + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,0,0,0); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple(sCopy, toSimple(termCopy)); + + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,0,0,5); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple("01234", toSimple(termCopy)); + + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,0,0,2); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple("01cde", toSimple(termCopy)); + + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,0,1,2); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple("a01de", toSimple(termCopy)); + + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,1,1,2); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple("a12de", toSimple(termCopy)); + + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,1,1,4); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple("a1234", toSimple(termCopy)); + + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,2,1,4); + assertEqualsSimple(s, toSimple(term)); + assertEqualsSimple("a2345", toSimple(termCopy)); + + try { + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,1,1,5); + fail(); + } catch (RuntimeException e) {} + try { + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,0,0,6); + fail(); + } catch (RuntimeException e) {} + try { + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,7,0,1); + fail(); + } catch (RuntimeException e) {} + try { + fillSimple(termCopy, sCopy); + termCopy.copyRange(term,0,7,1); + fail(); + } catch (RuntimeException e) {} + } + public void testCopyLine() { + ITerminalTextData term=makeITerminalTextData(); + String s= + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555"; + fill(term, s); + ITerminalTextData dest=makeITerminalTextData(); + String sCopy= + "aaa\n" + + "bbb\n" + + "ccc\n" + + "ddd\n" + + "eee"; + fill(dest, sCopy); + copySelective(dest,term,0,0,new boolean []{true,true,false,false,true}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm( + "111\n" + + "222\n" + + "ccc\n" + + "ddd\n" + + "555", toMultiLineText(dest)); + + fill(dest, sCopy); + copySelective(dest,term,0,0,new boolean []{true,true,true,true,true}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm(s, toMultiLineText(dest)); + + fill(dest, sCopy); + copySelective(dest,term,0,0,new boolean []{false,false,false,false,false}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm(sCopy, toMultiLineText(dest)); + } + protected void copySelective(ITerminalTextData dest, ITerminalTextData source, int sourceStartLine, int destStartLine, boolean[] linesToCopy) { + for (int i = 0; i < linesToCopy.length; i++) { + if(linesToCopy[i]) { + dest.copyLine(source, i+sourceStartLine, i+destStartLine); + } + } + } + + public void testCopyLineWithOffset() { + ITerminalTextData term=makeITerminalTextData(); + String s= + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555"; + fill(term, s); + ITerminalTextData dest=makeITerminalTextData(); + String sCopy= + "aaa\n" + + "bbb\n" + + "ccc\n" + + "ddd\n" + + "eee"; + fill(dest, sCopy); + copySelective(dest,term,1,0,new boolean []{true,false,false,true}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm( + "222\n" + + "bbb\n" + + "ccc\n" + + "555\n" + + "eee", toMultiLineText(dest)); + + fill(dest, sCopy); + copySelective(dest,term,2,0,new boolean []{true,true}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm( + "333\n" + + "444\n" + + "ccc\n" + + "ddd\n" + + "eee", toMultiLineText(dest)); + + fill(dest, sCopy); + copySelective(dest,term,0,0,new boolean []{true,true,true,true,true}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm(s, toMultiLineText(dest)); + + fill(dest, sCopy); + copySelective(dest,term,0,0,new boolean []{false,false,false,false,false}); + assertEqualsTerm(s, toMultiLineText(term)); + assertEqualsTerm(sCopy, toMultiLineText(dest)); + } + public void testScrollNoop() { + scrollTest(0,0,0, "012345","012345"); + scrollTest(0,1,0, "012345","012345"); + scrollTest(0,6,0, "012345","012345"); + } + public void testScrollAll() { + scrollTest(0,6,1, "012345"," 01234"); + scrollTest(0,6,-1, "012345","12345 "); + scrollTest(0,6,2, "012345"," 0123"); + scrollTest(0,6,-2, "012345","2345 "); + } + public void testScrollNegative() { + scrollTest(0,2,-1,"012345","1 2345"); + scrollTest(0,1,-1,"012345"," 12345"); + scrollTest(0,6,-1,"012345","12345 "); + scrollTest(0,6,-6,"012345"," "); + scrollTest(0,6,-7,"012345"," "); + scrollTest(0,6,-8,"012345"," "); + scrollTest(0,6,-2,"012345","2345 "); + scrollTest(1,1,-1,"012345","0 2345"); + scrollTest(1,1,-1,"012345","0 2345"); + scrollTest(1,2,-1,"012345","02 345"); + scrollTest(5,1,-1,"012345","01234 "); + scrollTest(5,1,-1,"012345","01234 "); + } + public void testScrollNegative2() { + scrollTest(0,2,-1," 23 "," 23 "); + scrollTest(0,1,-1," 23 "," 23 "); + scrollTest(0,6,-1," 23 "," 23 "); + scrollTest(0,6,-6," 23 "," "); + scrollTest(0,6,-7," 23 "," "); + scrollTest(0,6,-8," 23 "," "); + scrollTest(0,6,-2," 23 ","23 "); + scrollTest(1,1,-1," 23 "," 23 "); + scrollTest(1,2,-1," 23 "," 2 3 "); + scrollTest(5,1,-1," 23 "," 23 "); + scrollTest(5,1,-1," 23 "," 23 "); + } + public void testScrollNegative3() { + scrollTest(1,5,-7,"012345","0 "); + } + public void testScrollPositive2() { + scrollTest(2,8,20, "0123456789", "01 "); + } + public void testScrollPositive() { + scrollTest(0,2,1, "012345", " 02345"); + scrollTest(0,2,2, "012345", " 2345"); + scrollTest(2,4,2, "012345", "01 23"); + scrollTest(2,4,2, "0123456", "01 236"); + scrollTest(0,7,6, "0123456", " 0"); + scrollTest(0,7,8, "0123456", " "); + scrollTest(0,7,9, "0123456", " "); + scrollTest(2,4,2, "0123456", "01 236"); + scrollTest(2,5,3, "0123456789", "01 23789"); + scrollTest(2,7,3, "0123456789", "01 23459"); + scrollTest(2,8,3, "0123456789", "01 23456"); + scrollTest(2,8,5, "0123456789", "01 234"); + scrollTest(2,8,9, "0123456789", "01 "); + scrollTest(0,10,9,"0123456789", " 0"); + scrollTest(0,6,6, "012345", " "); + } + public void testScrollFail() { + try { + scrollTest(5,2,-1,"012345","012345"); + fail(); + } catch (RuntimeException e) { + } + try { + scrollTest(0,7,1,"012345"," "); + fail(); + } catch (RuntimeException e) { + } + } + /** + * Makes a simple shift test + * @param line scroll start + * @param n number of lines to be scrolled + * @param shift amount of lines to be shifted + * @param start the original data + * @param result the expected result + */ + void scrollTest(int line,int n, int shift, String start,String result) { + ITerminalTextData term=makeITerminalTextData(); + fillSimple(term,start); + term.scroll(line, n, shift); + assertEqualsSimple(result, toSimple(term)); + } + + public void testWrappedLines() { + ITerminalTextData term=makeITerminalTextData(); + term.setDimensions(4, 4); + for (int i=0; i=windowStart && iTIME) { + System.out.println(label+" "+(n*1000)/(System.currentTimeMillis()-t0)+" setChar()/sec "+ N); + break; + } + } + } + public void testPerformance1() { + ITerminalTextData term=new TerminalTextData(); + method1(term, "1 "); + } + public void testPerformance1a() { + ITerminalTextData term=new TerminalTextData(); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + method1(term, "1a"); + snapshot.updateSnapshot(true); + } + public void testPerformance1b() { + ITerminalTextData term=new TerminalTextData(); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + N=0; + snapshot.addListener(new ITerminalTextDataSnapshot.SnapshotOutOfDateListener(){ + public void snapshotOutOfDate(ITerminalTextDataSnapshot snapshot) { + N++; + }}); + method1(term, "1b"); + snapshot.updateSnapshot(true); + } + private void method1(ITerminalTextData term, String label) { + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + initPerformance(term); + String s="This is a test string"; + long n=0; + long t0=System.currentTimeMillis(); + char[] chars=new char[term.getWidth()]; + for (int i = 0; i < 10000000; i++) { + for (int j = 0; j < chars.length; j++) { + chars[j]=s.charAt((i+j)%s.length()); + } + for (int line = 0; line < term.getHeight(); line++) { + term.setChars(line, 0, chars, style); + n+=chars.length; + } + if(System.currentTimeMillis()-t0>TIME) { + System.out.println(label+" "+(n*1000)/(System.currentTimeMillis()-t0)+" setChars()/sec "+ N); + break; + } + } + } + public void testPerformance2() { + TerminalTextData term=new TerminalTextData(); + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + initPerformance(term); + TerminalTextData copy=new TerminalTextData(); + copy.copy(term); + + String s="This is a test string"; + long n=0; + long t0=System.currentTimeMillis(); + char[] chars=new char[term.getWidth()]; + for (int i = 0; i < 10000000; i++) { + for (int j = 0; j < chars.length; j++) { + chars[j]=s.charAt((i+j)%s.length()); + } + for (int line = 0; line < term.getHeight(); line++) { + term.setChars(line, 0, chars, 0,1,style); + copy.copy(term); + n+=1; + if(System.currentTimeMillis()-t0>TIME) { + System.out.println((n*1000)/(System.currentTimeMillis()-t0)+" copy()/sec"); + return; + } + } + } + } + public void testPerformance2a() { + TerminalTextData term=new TerminalTextData(); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + initPerformance(term); + TerminalTextData copy=new TerminalTextData(); + copy.copy(term); + + String s="This is a test string"; + long n=0; + long t0=System.currentTimeMillis(); + char[] chars=new char[term.getWidth()]; + for (int i = 0; i < 10000000; i++) { + for (int j = 0; j < chars.length; j++) { + chars[j]=s.charAt((i+j)%s.length()); + } + for (int line = 0; line < term.getHeight(); line++) { + term.setChars(line, 0, chars, 0,1,style); + copy.copy(term); + n+=1; + if(System.currentTimeMillis()-t0>TIME) { + System.out.println((n*1000)/(System.currentTimeMillis()-t0)+" copy()/sec"); + return; + } + } + } + snapshot.updateSnapshot(true); + } + int N=0; + public void testPerformance2b() { + TerminalTextData term=new TerminalTextData(); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + N=0; + snapshot.addListener(new ITerminalTextDataSnapshot.SnapshotOutOfDateListener(){ + public void snapshotOutOfDate(ITerminalTextDataSnapshot snapshot) { + N++; + }}); + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + initPerformance(term); + TerminalTextData copy=new TerminalTextData(); + copy.copy(term); + + String s="This is a test string"; + long n=0; + long t0=System.currentTimeMillis(); + char[] chars=new char[term.getWidth()]; + for (int i = 0; i < 10000000; i++) { + for (int j = 0; j < chars.length; j++) { + chars[j]=s.charAt((i+j)%s.length()); + } + for (int line = 0; line < term.getHeight(); line++) { + term.setChars(line, 0, chars, 0,1,style); + copy.copy(term); + n+=1; + if(System.currentTimeMillis()-t0>TIME) { + System.out.println((n*1000)/(System.currentTimeMillis()-t0)+" copy()/sec "+n); + return; + } + } + } + snapshot.updateSnapshot(true); + } + public void testPerformance3() { + TerminalTextData term=new TerminalTextData(); + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + initPerformance(term); + TerminalTextData copy=new TerminalTextData(); + copy.copy(term); + String s="This is a test string"; + long n=0; + long t0=System.currentTimeMillis(); + char[] chars=new char[term.getWidth()]; + for (int i = 0; i < 10000000; i++) { + boolean[] linesToCopy=new boolean[term.getHeight()]; + for (int j = 0; j < chars.length; j++) { + chars[j]=s.charAt((i+j)%s.length()); + } + for (int line = 0; line < term.getHeight(); line++) { + term.setChars(line, 0, chars, 0,1,style); + linesToCopy[line]=true; + copy.copyLine(term,0,0); + linesToCopy[line]=false; + n+=1; + if(System.currentTimeMillis()-t0>TIME) { + System.out.println((n*1000)/(System.currentTimeMillis()-t0)+" copy()/sec"); + return; + } + } + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataSnapshotTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataSnapshotTest.java new file mode 100644 index 00000000000..7f5b27de933 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataSnapshotTest.java @@ -0,0 +1,1344 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import junit.framework.TestCase; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +public class TerminalTextDataSnapshotTest extends TestCase { + String toMultiLineText(ITerminalTextDataReadOnly term) { + return TerminalTextTestHelper.toMultiLineText(term); + } + + protected ITerminalTextData makeITerminalTextData() { + return new TerminalTextData(); + } + + + public void testTerminalTextDataSnapshot() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + assertEquals(toMultiLineText(term), toMultiLineText(snapshot)); + + // new snapshots are fully changed + assertEquals(0,snapshot.getFirstChangedLine()); + assertEquals(term.getHeight()-1,snapshot.getLastChangedLine()); + for (int line = 0; line <= snapshot.getLastChangedLine(); line++) { + assertTrue(snapshot.hasLineChanged(line)); + } + // nothing has scrolled + assertEquals(0, snapshot.getScrollWindowSize()); + } + + public void testDetach() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + assertEquals(toMultiLineText(term),toMultiLineText(snapshot)); + snapshot.detach(); + // after detach changes to the term has no effect + term.setChar(0, 0, '?', null); + assertEquals(s, toMultiLineText(snapshot)); + term.setDimensions(2, 2); + assertEquals(s, toMultiLineText(snapshot)); + } + public void testIsOutOfDate() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + + assertFalse(snapshot.isOutOfDate()); + + // make a change and expect it to be changed + term.setChar(0, 0, '?', null); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + + // make a change and expect it to be changed + term.setChars(1, 1, new char[]{'?','!','.'},null); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + + // scroll + term.scroll(1, 2, -1); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + + // scroll + term.scroll(1, 2, 1); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + + // scroll + term.scroll(1, 2, -1); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(true); + assertFalse(snapshot.isOutOfDate()); + + // scroll + term.scroll(1, 2, 1); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(true); + assertFalse(snapshot.isOutOfDate()); + + // setDimensions + term.setDimensions(2, 2); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + + // setDimensions + term.setDimensions(20, 20); + assertTrue(snapshot.isOutOfDate()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + + } + ITerminalTextDataSnapshot snapshot(String text, ITerminalTextData term) { + TerminalTextTestHelper.fill(term,text); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + return snapshot; + + } + public void testUpdateSnapshot() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + String termString=toMultiLineText(term); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + assertEquals(termString,toMultiLineText(snapshot)); + + // make changes and assert that the snapshot has not changed + // then update the snapshot and expect it to be the + // same as the changed terminal + + // make a change + term.setChar(0, 0, '?', null); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(false); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // make a change + term.setChars(1, 1, new char[]{'?','!','.'},null); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(false); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // scroll + term.scroll(1, 2, -1); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(false); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // scroll + term.scroll(1, 2, 1); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(false); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // scroll + term.scroll(1, 2, -1); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(true); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // scroll + term.scroll(1, 2, 1); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(true); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // set dimensions + term.setDimensions(2, 2); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(false); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + + // set dimensions + term.setDimensions(20, 20); + assertEquals(termString,toMultiLineText(snapshot)); + + snapshot.updateSnapshot(false); + termString=toMultiLineText(term); + assertEquals(termString,toMultiLineText(snapshot)); + } + + public void testMaxSize() { + String s= + "111\n" + + "222\n" + + "333\n" + + "444\n" + + "555"; + ITerminalTextData term=makeITerminalTextData(); + term.setMaxHeight(8); + TerminalTextTestHelper.fill(term, s); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertEquals(toMultiLineText(term), toMultiLineText(snapshot)); + + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertEquals(toMultiLineText(term), toMultiLineText(snapshot)); + + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertEquals(toMultiLineText(term), toMultiLineText(snapshot)); + + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertEquals(toMultiLineText(term), toMultiLineText(snapshot)); + + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertEquals(toMultiLineText(term), toMultiLineText(snapshot)); + + } + + + public void testGetChar() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + ITerminalTextData termUnchanged=makeITerminalTextData(); + TerminalTextTestHelper.fill(termUnchanged,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + for (int line = 0; line < snapshot.getHeight(); line++) { + for (int column = 0; column < snapshot.getWidth(); column++) { + assertEquals(term.getChar(line, column),snapshot.getChar(line, column)); + } + } + // make a change + term.setChar(0, 0, '?', null); + // check against unchanged data + for (int line = 0; line < snapshot.getHeight(); line++) { + for (int column = 0; column < snapshot.getWidth(); column++) { + assertEquals(termUnchanged.getChar(line, column),snapshot.getChar(line, column)); + } + } + // update and compare against the terminal + snapshot.updateSnapshot(true); + for (int line = 0; line < snapshot.getHeight(); line++) { + for (int column = 0; column < snapshot.getWidth(); column++) { + assertEquals(term.getChar(line, column),snapshot.getChar(line, column)); + } + } + + } + + public void testGetHeight() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + int expectedHeight=term.getHeight(); + assertEquals(expectedHeight, snapshot.getHeight()); + term.setDimensions(term.getHeight()-1, term.getWidth()); + assertEquals(expectedHeight, snapshot.getHeight()); + + // + snapshot.updateSnapshot(false); + expectedHeight=term.getHeight(); + assertEquals(expectedHeight, snapshot.getHeight()); + term.setDimensions(term.getHeight()-1, term.getWidth()); + assertEquals(expectedHeight, snapshot.getHeight()); + } +// +// public void testGetLineSegments() { +// fail("Not yet implemented"); +// } +// + public void testGetStyle() { + ITerminalTextData term=makeITerminalTextData(); + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + term.setDimensions(6, 3); + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + char c=(char)('a'+column+line); + term.setChar(line, column, c, style.setForground(StyleColor.getStyleColor(""+c))); + } + } + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + + for (int line = 0; line < term.getHeight(); line++) { + for (int column = 0; column < term.getWidth(); column++) { + char c=(char)('a'+column+line); + assertSame(style.setForground(StyleColor.getStyleColor(""+c)), snapshot.getStyle(line, column)); + } + } + + } + + public void testGetWidth() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + int expectedWidth=term.getWidth(); + assertEquals(expectedWidth, snapshot.getWidth()); + term.setDimensions(term.getHeight(), term.getWidth()-1); + assertEquals(expectedWidth, snapshot.getWidth()); + + // + snapshot.updateSnapshot(false); + expectedWidth=term.getWidth(); + assertEquals(expectedWidth, snapshot.getWidth()); + term.setDimensions(term.getHeight(), term.getWidth()-1); + assertEquals(expectedWidth, snapshot.getWidth()); + } + + public void testGetFirstChangedLine() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + ITerminalTextDataSnapshot snapshot=snapshot(s,term); + + + assertEquals(0, snapshot.getFirstChangedLine()); + + // if nothing has changed the first changed line i height + snapshot.updateSnapshot(false); + assertEquals(Integer.MAX_VALUE, snapshot.getFirstChangedLine()); + + snapshot=snapshot(s,term); + term.setChar(0, 0, 'x', null); + snapshot.updateSnapshot(false); + assertEquals(0, snapshot.getFirstChangedLine()); + + snapshot=snapshot(s,term); + term.setChar(3, 0, 'x', null); + term.setChar(4, 0, 'x', null); + snapshot.updateSnapshot(false); + assertEquals(3, snapshot.getFirstChangedLine()); + + snapshot=snapshot(s,term); + term.scroll(0, 1, -1); + snapshot.updateSnapshot(false); + assertEquals(0, snapshot.getFirstChangedLine()); + + snapshot=snapshot(s,term); + term.scroll(2, 2, -1); + snapshot.updateSnapshot(false); + assertEquals(2, snapshot.getFirstChangedLine()); + + // when scrolling the end of the region 'has changed' + snapshot=snapshot(s,term); + term.scroll(2, 2, -1); + snapshot.updateSnapshot(true); + assertEquals(3, snapshot.getFirstChangedLine()); + + // when scrolling the end of the region 'has changed' + snapshot=snapshot(s,term); + term.scroll(2, 2, -1); + term.setChar(1, 0, 'x', null); + snapshot.updateSnapshot(true); + assertEquals(1, snapshot.getFirstChangedLine()); + + } + public void testGetLastChangedLine() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + ITerminalTextDataSnapshot snapshot=snapshot(s,term); + + + assertEquals(4, snapshot.getLastChangedLine()); + + // if nothing has changed the first changed line i height + snapshot.updateSnapshot(false); + assertEquals(-1, snapshot.getLastChangedLine()); + + snapshot=snapshot(s,term); + term.setChar(0, 0, 'x', null); + snapshot.updateSnapshot(false); + assertEquals(0, snapshot.getLastChangedLine()); + + snapshot=snapshot(s,term); + term.cleanLine(1); + snapshot.updateSnapshot(false); + assertEquals(1, snapshot.getLastChangedLine()); + + snapshot=snapshot(s,term); + term.setChar(3, 0, 'x', null); + term.setChar(4, 0, 'x', null); + snapshot.updateSnapshot(false); + assertEquals(4, snapshot.getLastChangedLine()); + + snapshot=snapshot(s,term); + term.scroll(0, 1, -1); + snapshot.updateSnapshot(false); + assertEquals(0, snapshot.getLastChangedLine()); + + snapshot=snapshot(s,term); + term.scroll(2, 2, -1); + snapshot.updateSnapshot(false); + assertEquals(3, snapshot.getLastChangedLine()); + + // when scrolling the end of the region 'has changed' + snapshot=snapshot(s,term); + term.scroll(2, 2, -1); + snapshot.updateSnapshot(true); + assertEquals(3, snapshot.getLastChangedLine()); + + // when scrolling the end of the region 'has changed' + snapshot=snapshot(s,term); + term.scroll(2, 2, -1); + term.setChar(1, 0, 'x', null); + snapshot.updateSnapshot(true); + assertEquals(3, snapshot.getLastChangedLine()); + + } + /** + * @param snapshot + * @param expected a string of 0 and 1 (1 means changed) + */ + void assertChangedLines(ITerminalTextDataSnapshot snapshot, String expected) { + assertEquals(expected.length(),snapshot.getHeight()); + StringBuffer buffer=new StringBuffer(); + for (int line = 0; line < expected.length(); line++) { + if(snapshot.hasLineChanged(line)) + buffer.append('1'); + else + buffer.append('0'); + } + assertEquals(expected, buffer.toString()); + } + public void testHasLineChangedScroll() { + ITerminalTextData term=makeITerminalTextData(); + String s="00\n" + + "11\n" + + "22\n" + + "33\n" + + "44\n" + + "55\n" + + "66\n" + + "77\n" + + "88\n" + + "99"; + ITerminalTextDataSnapshot snapshot=snapshot(s,term); + + term.scroll(2,3,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0000100000"); + + snapshot=snapshot(s,term); + term.scroll(2,3,-2); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0001100000"); + + snapshot=snapshot(s,term); + term.scroll(2,4,-1); + term.scroll(2,4,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0000110000"); + + term.scroll(2,3,1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0011100000"); + + snapshot=snapshot(s,term); + term.scroll(2,3,2); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0011100000"); + + snapshot=snapshot(s,term); + term.scroll(2,4,1); + term.scroll(2,4,1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0011110000"); + + + snapshot=snapshot(s,term); + term.scroll(2,3,-1); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot, "0011100000"); + + snapshot=snapshot(s,term); + term.scroll(2,3,-2); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot, "0011100000"); + + snapshot=snapshot(s,term); + term.scroll(2,4,-1); + term.scroll(2,4,-1); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot, "0011110000"); + } + public void testMultiScrollWithDifferentSizes() { + ITerminalTextData term=makeITerminalTextData(); + String s="00\n" + + "11\n" + + "22\n" + + "33\n" + + "44\n" + + "55\n" + + "66\n" + + "77\n" + + "88\n" + + "99"; + ITerminalTextDataSnapshot snapshot; + + snapshot=snapshot(s,term); + term.scroll(2,6,-1); + term.scroll(2,5,-1); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot, "0011111100"); + assertEquals(2, snapshot.getFirstChangedLine()); + assertEquals(7, snapshot.getLastChangedLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowShift()); + + // scrolls with different ranges cause no scroll + // optimization + snapshot=snapshot(s,term); + term.scroll(2,6,-1); + term.scroll(2,5,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0011111100"); + assertEquals(2, snapshot.getFirstChangedLine()); + assertEquals(7, snapshot.getLastChangedLine()); + assertEquals(0, snapshot.getScrollWindowShift()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowStartLine()); + } + public void testHasLineChanged() { + ITerminalTextData term=makeITerminalTextData(); + String s="000000\n" + + "111111\n" + + "222222\n" + + "333333\n" + + "444444\n" + + "555555\n" + + "666666\n" + + "777777\n" + + "888888\n" + + "999999"; + ITerminalTextDataSnapshot snapshot; + + snapshot=snapshot(s,term); + term.scroll(2,3,-1); + term.setChar(7, 0, '.', null); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0000100100"); + + snapshot=snapshot(s,term); + term.scroll(2,3,-2); + term.setChar(9, 0, '.', null); + term.setChars(0, 0, new char[]{'.','!'}, null); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1001100001"); + + snapshot=snapshot(s,term); + term.scroll(2,4,-1); + term.scroll(2,4,-1); + term.setChars(2, 2, new char[]{'.','!','*'},1,1, null); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0010110000"); + + snapshot=snapshot(s,term); + term.scroll(2,7,-1); + term.setChar(5, 2, '.', null); + term.scroll(2,7,-2); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0001001110"); + + + snapshot=snapshot(s,term); + term.scroll(2,7,-1); + term.setChar(5, 2, '.', null); + term.scroll(2,7,-2); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot, "0011111110"); + + } + + public void testScroll() { + ITerminalTextData term=makeITerminalTextData(); + String s="00\n" + + "11\n" + + "22\n" + + "33\n" + + "44\n" + + "55\n" + + "66\n" + + "77\n" + + "88\n" + + "99"; + ITerminalTextDataSnapshot snapshot=snapshot(s,term); + + term.scroll(2,3,-1); + snapshot.updateSnapshot(true); + assertEquals(2, snapshot.getScrollWindowStartLine()); + assertEquals(3, snapshot.getScrollWindowSize()); + assertEquals(-1, snapshot.getScrollWindowShift()); + assertEquals(4, snapshot.getFirstChangedLine()); + assertEquals(4, snapshot.getLastChangedLine()); + + term.scroll(2,3,-2); + snapshot.updateSnapshot(true); + assertEquals(2, snapshot.getScrollWindowStartLine()); + assertEquals(3, snapshot.getScrollWindowSize()); + assertEquals(-2, snapshot.getScrollWindowShift()); + assertEquals(3, snapshot.getFirstChangedLine()); + assertEquals(4, snapshot.getLastChangedLine()); + + term.scroll(2,4,-1); + term.scroll(2,4,-1); + snapshot.updateSnapshot(true); + assertEquals(2, snapshot.getScrollWindowStartLine()); + assertEquals(4, snapshot.getScrollWindowSize()); + assertEquals(-2, snapshot.getScrollWindowShift()); + assertEquals(4, snapshot.getFirstChangedLine()); + assertEquals(5, snapshot.getLastChangedLine()); + + + snapshot=snapshot(s,term); + term.scroll(2,3,-1); + snapshot.updateSnapshot(false); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + assertEquals(2, snapshot.getFirstChangedLine()); + assertEquals(4, snapshot.getLastChangedLine()); + + } + public void testDisjointScroll() { + ITerminalTextData term=makeITerminalTextData(); + String s="000000\n" + + "111111\n" + + "222222\n" + + "333333\n" + + "444444\n" + + "555555\n" + + "666666\n" + + "777777\n" + + "888888\n" + + "999999"; + ITerminalTextDataSnapshot snapshot; + + snapshot=snapshot(s,term); + term.scroll(0,2,-1); + term.scroll(4,2,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1100110000"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.scroll(0,3,-1); + term.scroll(2,2,-2); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1111000000"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.scroll(0,3,-1); + term.scroll(2,2,-2); + term.scroll(0,3,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1111000000"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.scroll(0,3,-1); + term.scroll(2,2,-2); + term.scroll(0,3,-10); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1111000000"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.scroll(1,3,-1); + term.scroll(1,3,1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "0111000000"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + } + public void testResize() { + ITerminalTextData term=makeITerminalTextData(); + String s="000000\n" + + "111111\n" + + "222222\n" + + "333333"; + ITerminalTextDataSnapshot snapshot; + + snapshot=snapshot(s,term); + term.setDimensions(term.getHeight(), term.getWidth()+1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1111"); + assertEquals(0, snapshot.getFirstChangedLine()); + assertEquals(3, snapshot.getLastChangedLine()); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.setDimensions(term.getHeight()+1, term.getWidth()); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "11111"); + assertEquals(0, snapshot.getFirstChangedLine()); + assertEquals(4, snapshot.getLastChangedLine()); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.setDimensions(term.getHeight()-1, term.getWidth()); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "111"); + assertEquals(0, snapshot.getFirstChangedLine()); + assertEquals(2, snapshot.getLastChangedLine()); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.setDimensions(0, 0); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, ""); + assertEquals(0, snapshot.getFirstChangedLine()); + assertEquals(-1, snapshot.getLastChangedLine()); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + } + public void testResizeAfterScroll() { + ITerminalTextData term=makeITerminalTextData(); + String s="000000\n" + + "111111\n" + + "222222\n" + + "333333\n" + + "444444\n" + + "555555\n" + + "666666\n" + + "777777\n" + + "888888\n" + + "999999"; + ITerminalTextDataSnapshot snapshot; + + snapshot=snapshot(s,term); + term.scroll(1,2,-1); + term.setDimensions(5, 4); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "11111"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + + snapshot=snapshot(s,term); + term.scroll(1,2,-1); + term.setDimensions(7, 2); + term.scroll(4,2,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1111111"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + snapshot=snapshot(s,term); + + term.scroll(1,2,-1); + term.setDimensions(term.getHeight(),term.getWidth()+1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "1111111111"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + } + public void testScrollAfterResize() { + ITerminalTextData term=makeITerminalTextData(); + String s="000000\n" + + "111111\n" + + "222222\n" + + "333333\n" + + "444444\n" + + "555555\n" + + "666666\n" + + "777777\n" + + "888888\n" + + "999999"; + ITerminalTextDataSnapshot snapshot; + + snapshot=snapshot(s,term); + term.setDimensions(14, 6); + term.scroll(0,14,-1); + snapshot.updateSnapshot(true); + assertChangedLines(snapshot, "11111111111111"); + assertEquals(0, snapshot.getScrollWindowStartLine()); + assertEquals(0, snapshot.getScrollWindowSize()); + assertEquals(0, snapshot.getScrollWindowShift()); + } + private final class SnapshotListener implements ITerminalTextDataSnapshot.SnapshotOutOfDateListener { + int N; + public void snapshotOutOfDate(ITerminalTextDataSnapshot snapshot) { + N++; + } + public void reset() { + N=0; + } + } + + public void testAddListener() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + SnapshotListener listener=new SnapshotListener(); + snapshot.addListener(listener); + assertEquals(0, listener.N); + + // make a change and expect it to be changed + term.setChar(0, 0, '?', null); + assertEquals(1, listener.N); + term.setChar(1, 1, '?', null); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // make a change and expect it to be changed + term.setChars(1, 1, new char[]{'?','!','.'},null); + assertEquals(1, listener.N); + term.setChars(2, 1, new char[]{'?','!','.'},null); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // scroll + term.scroll(1, 2, -1); + assertEquals(1, listener.N); + term.scroll(1, 2, -1); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // scroll + term.scroll(1, 2, 1); + assertEquals(1, listener.N); + term.scroll(1, 2, 1); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // scroll + term.scroll(1, 2, -1); + assertEquals(1, listener.N); + term.scroll(1, 2, -1); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // scroll + term.scroll(1, 2, 1); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // setDimensions + term.setDimensions(2, 2); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener.N); + listener.reset(); + + // setDimensions + term.setDimensions(20, 20); + assertEquals(1, listener.N); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + } + + public void testRemoveListener() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + + SnapshotListener listener1=new SnapshotListener(); + SnapshotListener listener2=new SnapshotListener(); + SnapshotListener listener3=new SnapshotListener(); + snapshot.addListener(listener1); + snapshot.addListener(listener2); + snapshot.addListener(listener3); + assertEquals(0, listener1.N); + + // make a change and expect it to be changed + term.setChar(0, 0, '?', null); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + term.setChar(1, 1, '?', null); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + listener1.reset(); + listener2.reset(); + listener3.reset(); + + // make a change and expect it to be changed + term.setChars(1, 1, new char[]{'?','!','.'},null); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + term.setChars(2, 1, new char[]{'?','!','.'},null); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + listener1.reset(); + listener2.reset(); + listener3.reset(); + + snapshot.removeListener(listener2); + + // scroll + term.scroll(1, 2, -1); + assertEquals(1, listener1.N); + assertEquals(0, listener2.N); + assertEquals(1, listener3.N); + + term.scroll(1, 2, -1); + assertEquals(1, listener1.N); + assertEquals(0, listener2.N); + assertEquals(1, listener3.N); + + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(0, listener2.N); + assertEquals(1, listener3.N); + + snapshot.addListener(listener2); + listener1.reset(); + listener2.reset(); + listener3.reset(); + + + snapshot.removeListener(listener3); + // scroll + term.scroll(1, 2, 1); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(0, listener3.N); + + term.scroll(1, 2, 1); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(0, listener3.N); + + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(0, listener3.N); + + snapshot.addListener(listener3); + listener1.reset(); + listener2.reset(); + listener3.reset(); + + // add listener multiple times + snapshot.addListener(listener3); + + // scroll + term.scroll(1, 2, -1); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(2, listener3.N); + + term.scroll(1, 2, -1); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(2, listener3.N); + + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(2, listener3.N); + + listener1.reset(); + listener2.reset(); + listener3.reset(); + // remove the duplicate listener + snapshot.removeListener(listener3); + + + // scroll + term.scroll(1, 2, 1); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + listener1.reset(); + listener2.reset(); + listener3.reset(); + + + // setDimensions + term.setDimensions(2, 2); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + + snapshot.updateSnapshot(false); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + listener1.reset(); + listener2.reset(); + listener3.reset(); + + + // setDimensions + term.setDimensions(20, 20); + assertEquals(1, listener1.N); + assertEquals(1, listener2.N); + assertEquals(1, listener3.N); + + + snapshot.updateSnapshot(false); + assertFalse(snapshot.isOutOfDate()); + } + public void testWindowOfInterest() { + ITerminalTextData term=makeITerminalTextData(); + TerminalTextTestHelper.fillSimple(term,"0123456789"); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + snapshot.setInterestWindow(7, 4); + snapshot.setInterestWindow(9, 4); + snapshot.updateSnapshot(false); + } + public void testWindowOfInterest2() { + ITerminalTextData term=makeITerminalTextData(); + TerminalTextTestHelper.fillSimple(term,"0123456789"); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + snapshot.updateSnapshot(false); + term.scroll(7, 3,-1); + snapshot.setInterestWindow(9, 4); + snapshot.updateSnapshot(false); + } + public void testAddLine() { + ITerminalTextData term=makeITerminalTextData(); + TerminalTextTestHelper.fillSimple(term,"0123456789"); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + term.setMaxHeight(20); + snapshot.updateSnapshot(false); + assertEquals(10,term.getHeight()); + assertEquals(20,term.getMaxHeight()); + assertFalse(snapshot.isOutOfDate()); + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + assertEquals(11,term.getHeight()); + assertEquals(10,snapshot.getHeight()); + snapshot.updateSnapshot(false); + assertEquals(11,term.getHeight()); + assertEquals(11,snapshot.getHeight()); + assertEquals(20,term.getMaxHeight()); + + term.addLine(); + term.addLine(); + assertEquals(11,snapshot.getHeight()); + assertEquals(13,term.getHeight()); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertEquals(13,snapshot.getHeight()); + assertEquals(13,term.getHeight()); + assertEquals(20,term.getMaxHeight()); + } + public void testHasDimensionsChanged() { + ITerminalTextData term=makeITerminalTextData(); + TerminalTextTestHelper.fillSimple(term,"0123456789"); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + term.setMaxHeight(20); + snapshot.setInterestWindow(3, 4); + snapshot.updateSnapshot(false); + assertEquals(10,term.getHeight()); + assertEquals(20,term.getMaxHeight()); + assertFalse(snapshot.isOutOfDate()); + term.addLine(); + assertTrue(snapshot.isOutOfDate()); + assertEquals(11,term.getHeight()); + assertEquals(10,snapshot.getHeight()); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasDimensionsChanged()); + assertEquals(11,term.getHeight()); + assertEquals(11,snapshot.getHeight()); + assertEquals(20,term.getMaxHeight()); + + term.addLine(); + term.addLine(); + assertEquals(11,snapshot.getHeight()); + assertEquals(13,term.getHeight()); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasDimensionsChanged()); + assertEquals(13,snapshot.getHeight()); + assertEquals(13,term.getHeight()); + assertEquals(20,term.getMaxHeight()); + } + public void testCursor() { + ITerminalTextData term=makeITerminalTextData(); + TerminalTextTestHelper.fillSimple(term,"0123456789"); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + term.setMaxHeight(20); + snapshot.setInterestWindow(3, 4); + snapshot.updateSnapshot(false); + term.setCursorLine(2); + term.setCursorColumn(1); + snapshot.updateSnapshot(false); + assertEquals(2, snapshot.getCursorLine()); + assertEquals(1, snapshot.getCursorColumn()); + term.setCursorLine(3); + term.setCursorColumn(2); + snapshot.updateSnapshot(false); + assertEquals(3, snapshot.getCursorLine()); + assertEquals(2, snapshot.getCursorColumn()); + } + public void testCursor2() { + ITerminalTextData term=makeITerminalTextData(); + TerminalTextTestHelper.fillSimple(term,"0123456789"); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + term.setMaxHeight(20); + snapshot.setInterestWindow(3, 4); + snapshot.updateSnapshot(false); + term.setCursorLine(2); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + term.setCursorColumn(1); + assertTrue(snapshot.isOutOfDate()); + } + public void testHasTerminalChanged() { + ITerminalTextData term=makeITerminalTextData(); + String s="12345\n" + + "abcde\n" + + "ABCDE\n" + + "vwxzy\n" + + "VWXYZ"; + TerminalTextTestHelper.fill(term,s); + + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + assertTrue(snapshot.hasTerminalChanged()); + snapshot.updateSnapshot(false); + + assertTrue(snapshot.hasTerminalChanged()); + + // make a change and expect it to be changed + term.setChar(0, 0, '?', null); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasTerminalChanged()); + + // make a change and expect it to be changed + term.setChars(1, 1, new char[]{'?','!','.'},null); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasTerminalChanged()); + + // scroll + term.scroll(1, 2, -1); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasTerminalChanged()); + + // scroll + term.scroll(1, 2, 1); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasTerminalChanged()); + + // scroll + term.scroll(1, 2, -1); + snapshot.updateSnapshot(true); + assertTrue(snapshot.hasTerminalChanged()); + + // scroll + term.scroll(1, 2, 1); + snapshot.updateSnapshot(true); + assertTrue(snapshot.hasTerminalChanged()); + + // setDimensions + term.setDimensions(2, 2); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasTerminalChanged()); + + // setDimensions + term.setDimensions(20, 20); + snapshot.updateSnapshot(false); + assertTrue(snapshot.hasTerminalChanged()); + + snapshot.updateSnapshot(false); + assertFalse(snapshot.hasTerminalChanged()); + + // window of interest changes should NOT set hasTerminalChanged + snapshot.updateSnapshot(false); + snapshot.setInterestWindow(7, 4); + + assertFalse(snapshot.hasTerminalChanged()); + } + public void testGetTerminalTextData() { + ITerminalTextData term=makeITerminalTextData(); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + assertSame(term, snapshot.getTerminalTextData()); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataSnapshotWindowTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataSnapshotWindowTest.java new file mode 100644 index 00000000000..e788ec259a9 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataSnapshotWindowTest.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import junit.framework.TestCase; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataReadOnly; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; + +public class TerminalTextDataSnapshotWindowTest extends TestCase { + String toMultiLineText(ITerminalTextDataReadOnly term) { + return TerminalTextTestHelper.toMultiLineText(term); + } + String toSimpleText(ITerminalTextDataReadOnly term) { + return TerminalTextTestHelper.toSimple(term); + } + + protected ITerminalTextData makeITerminalTextData() { + return new TerminalTextData(); + } + ITerminalTextDataSnapshot snapshotSimple(String text, ITerminalTextData term) { + TerminalTextTestHelper.fillSimple(term,text); + ITerminalTextDataSnapshot snapshot=term.makeSnapshot(); + return snapshot; + + } + /** + * @param snapshot + * @param expected a string of 0 and 1 (1 means changed) + */ + void assertChangedLines(ITerminalTextDataSnapshot snapshot, String expected) { + assertEquals(expected.length(),snapshot.getHeight()); + StringBuffer buffer=new StringBuffer(); + for (int line = 0; line < expected.length(); line++) { + if(snapshot.hasLineChanged(line)) + buffer.append('1'); + else + buffer.append('0'); + } + assertEquals(expected, buffer.toString()); + } + + public void testSetInterestWindow() { + ITerminalTextData term=makeITerminalTextData(); + ITerminalTextDataSnapshot snapshot=snapshotSimple("0123456789",term); + assertEquals(0, snapshot.getInterestWindowStartLine()); + assertEquals(-1, snapshot.getInterestWindowSize()); + snapshot.setInterestWindow(2, 3); + assertEquals(2, snapshot.getInterestWindowStartLine()); + assertEquals(3, snapshot.getInterestWindowSize()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0011100000"); + } + public void testSetChar() { + ITerminalTextData term=makeITerminalTextData(); + ITerminalTextDataSnapshot snapshot=snapshotSimple("0123456789",term); + snapshot.setInterestWindow(2, 3); + snapshot.updateSnapshot(false); + assertEquals(" 234 ", toSimpleText(snapshot)); + + term.setChar(0, 0, 'x', null); + assertFalse(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0000000000"); + + term.setChar(1, 0, 'x', null); + assertFalse(snapshot.isOutOfDate()); + + term.setChar(2, 0, 'x', null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0010000000"); + + term.setChar(3, 0, 'x', null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0001000000"); + + term.setChar(4, 0, 'x', null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0000100000"); + + term.setChar(5, 0, 'x', null); + assertFalse(snapshot.isOutOfDate()); + + term.setChar(6, 0, 'x', null); + assertFalse(snapshot.isOutOfDate()); + + for (int i = 0; i < 9; i++) { + term.setChar(i, 0, (char)('a'+i), null); + } + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0011100000"); + } + + public void testSetChars() { + ITerminalTextData term=makeITerminalTextData(); + ITerminalTextDataSnapshot snapshot=snapshotSimple("0123456789",term); + snapshot.setInterestWindow(2, 3); + snapshot.updateSnapshot(false); + assertEquals(" 234 ", toSimpleText(snapshot)); + + term.setChars(0, 0, "x".toCharArray(), null); + assertFalse(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0000000000"); + + term.setChars(1, 0, "x".toCharArray(), null); + assertFalse(snapshot.isOutOfDate()); + + term.setChars(2, 0, "x".toCharArray(), null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0010000000"); + + term.setChars(3, 0, "x".toCharArray(), null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0001000000"); + + term.setChars(4, 0, "x".toCharArray(), null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0000100000"); + + term.setChars(5, 0, "x".toCharArray(), null); + assertFalse(snapshot.isOutOfDate()); + + term.setChars(6, 0, "x".toCharArray(), null); + assertFalse(snapshot.isOutOfDate()); + for (int i = 0; i < 9; i++) { + term.setChars(i, 0, (i+"").toCharArray(), null); + } + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0011100000"); + } + public void testSetChars2() { + ITerminalTextData term=makeITerminalTextData(); + ITerminalTextDataSnapshot snapshot=snapshotSimple("0123456789",term); + snapshot.setInterestWindow(2, 3); + snapshot.updateSnapshot(false); + assertEquals(" 234 ", toSimpleText(snapshot)); + + term.setChars(0, 0, "abcdef".toCharArray(),2,1, null); + assertFalse(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0000000000"); + + term.setChars(1, 0, "abcdef".toCharArray(),2 ,1, null); + assertFalse(snapshot.isOutOfDate()); + + term.setChars(2, 0, "abcdef".toCharArray(),2 ,1, null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0010000000"); + + term.setChars(3, 0, "abcdef".toCharArray(),2 ,1, null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0001000000"); + + term.setChars(4, 0, "abcdef".toCharArray(),2 ,1, null); + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0000100000"); + + term.setChars(5, 0, "abcdef".toCharArray(),2 ,1, null); + assertFalse(snapshot.isOutOfDate()); + + term.setChars(6, 0, "abcdef".toCharArray(),2 ,1, null); + assertFalse(snapshot.isOutOfDate()); + for (int i = 0; i < 9; i++) { + term.setChars(i, 0, ("ab"+i+"def").toCharArray(),2 ,1, null); + } + assertTrue(snapshot.isOutOfDate()); + snapshot.updateSnapshot(false); + assertChangedLines(snapshot,"0011100000"); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataStoreTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataStoreTest.java new file mode 100644 index 00000000000..997d961eced --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataStoreTest.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import org.eclipse.tm.terminal.model.ITerminalTextData; + +public class TerminalTextDataStoreTest extends AbstractITerminalTextDataTest { + protected ITerminalTextData makeITerminalTextData() { + return new TerminalTextDataStore(); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataTest.java new file mode 100644 index 00000000000..52f9283060a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataTest.java @@ -0,0 +1,20 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import org.eclipse.tm.terminal.model.ITerminalTextData; + +public class TerminalTextDataTest extends AbstractITerminalTextDataTest { + protected ITerminalTextData makeITerminalTextData() { + return new TerminalTextData(); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataWindowTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataWindowTest.java new file mode 100644 index 00000000000..23204cc2a5a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/model/TerminalTextDataWindowTest.java @@ -0,0 +1,496 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [168197] Fix Terminal for CDC-1.1/Foundation-1.1 + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.model; + +import java.util.ArrayList; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.LineSegment; +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +public class TerminalTextDataWindowTest extends AbstractITerminalTextDataTest { + int fOffset; + int fSize; + public TerminalTextDataWindowTest() { + fOffset=2; + fSize=2; + } + protected ITerminalTextData makeITerminalTextData() { + TerminalTextDataWindow term=new TerminalTextDataWindow(); + term.setWindow(fOffset,fSize); + return term; + } + /** + * Used for multi line text + * @param expected + * @param actual + */ + protected void assertEqualsTerm(String expected,String actual) { + assertEquals(stripMultiLine(expected), stripMultiLine(actual)); + } + private String stripMultiLine(String s) { + StringBuffer b=new StringBuffer(); + // String[] lines=s.split("\n"); + // + ArrayList l = new ArrayList(); + int j = 0; + for (int k = 0; k < s.length(); k++) { + if (s.charAt(k) == '\n') { + l.add(s.substring(j, k)); + j = k; + } + } + j = l.size() - 1; + while (j >= 0 && "".equals(l.get(j))) { + j--; + } + String[] lines = new String[j + 1]; + while (j >= 0) { + lines[j] = l.get(j); + j--; + } + // + for (int i = 0; i < lines.length; i++) { + if(i>0) + b.append("\n"); //$NON-NLS-1$ + if(i>=fOffset && i=fOffset && i=fOffset&&line=fOffset&&line=fOffset&&line0) + buff.append("\n"); //$NON-NLS-1$ + for (int column = 0; column < width; column++) { + buff.append(term.getChar(line, column)); + } + } + return buff.toString(); + } + static public String toSimple(String str) { + //return str.replaceAll("\000", " ").replaceAll("\n", ""); + // + StringBuffer buf = new StringBuffer(str.length()); + for (int i = 0; i < str.length(); i++) { + char c = str.charAt(i); + switch (c) { + case '\000': + buf.append(' '); + break; + case '\n': + break; + default: + buf.append(c); + break; + } + } + return buf.toString(); + // + } + /** + * @param term + * @param s each character is one line + */ + static public void fillSimple(ITerminalTextData term, String s) { + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + term.setDimensions(s.length(), 1); + for (int i = 0; i < s.length(); i++) { + char c=s.charAt(i); + term.setChar(i, 0, c, style.setForground(StyleColor.getStyleColor(""+c))); + } + } + /** + * @param term + * @param s lines separated by \n. The terminal will automatically + * resized to fit the text. + */ + static public void fill(ITerminalTextData term, String s) { + int width=0; + int len=0; + int height=0; + for (int i = 0; i < s.length(); i++) { + char c=s.charAt(i); + if(c=='\n') { + width=Math.max(width,len); + len=0; + } else { + if(len==0) + height++; + len++; + } + } + width=Math.max(width,len); + term.setDimensions(height, width); + fill(term,0,0,s); + } + + static public void fill(ITerminalTextData term, int column, int line, String s) { + int xx=column; + int yy=line; + Style style=Style.getStyle(StyleColor.getStyleColor("fg"), StyleColor.getStyleColor("bg"), false, false, false, false); + for (int i = 0; i < s.length(); i++) { + char c=s.charAt(i); + if(c=='\n') { + yy++; + xx=column; + } else { + term.setChar(yy, xx, c, style.setForground(StyleColor.getStyleColor(""+c))); + xx++; + } + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestConnection.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestConnection.java new file mode 100644 index 00000000000..39da95d6a21 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestConnection.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.speedtest; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; + +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; + +public class SpeedTestConnection extends Thread { + private static int fgNo; + private final ITerminalControl fControl; + private final InputStream fInputStream; + private final SpeedTestSettings fSettings; + protected SpeedTestConnection(InputStream inputStream, SpeedTestSettings settings,ITerminalControl control) { + super("SpeedTestConnection-"+fgNo++); + fControl = control; + fInputStream=inputStream; + fSettings=settings; + } + public void run() { + fControl.setState(TerminalState.CONNECTED); + + try { + readDataForever(fInputStream,fControl.getRemoteToTerminalOutputStream()); + } catch (IOException e) { + connectFailed(e.getMessage(),e.getMessage()); + } + // when reading is done, we set the state to closed + fControl.setState(TerminalState.CLOSED); + } + private void connectFailed(String terminalText, String msg) { + Logger.log(terminalText); + fControl.displayTextInTerminal(terminalText); + fControl.setState(TerminalState.CLOSED); + fControl.setMsg(msg); + } + /** + * Read the data from the input file and display it in the terminal. + * @param in + * @throws IOException + */ + private void readDataForever(InputStream in, OutputStream os) throws IOException { + long N=0; + long T=0; + long tDisplay=0; + int NCalls=0; + int bufferSize=fSettings.getBufferSize(); + int throttle=fSettings.getThrottle(); + // read the data + BufferedReader reader = new BufferedReader(new InputStreamReader(in)); + // read until the thread gets interrupted.... + String info=""; + int n=0; + byte[] crnl="\r\n".getBytes("UTF-8"); + long t0=System.currentTimeMillis(); + String line=null; + do { + line=reader.readLine(); + + // read some bytes + if(line!=null) { + os.write(line.getBytes("UTF-8")); + os.write(crnl); + n+=line.length(); + } + // process at least this number of characters to update the UI + if(line==null || n>bufferSize) { + if(throttle>0) + sleep(throttle); + // we assume we get ASCII UTF8 bytes + long t=System.currentTimeMillis(); + T+=t-t0; + N+=n; + NCalls++; + if(t-tDisplay>1000 && T>0) { + long rate=(1000*N)/T; + info=rate+" byte/s = "+rate*8+" baud "+"bytes/call="+N/NCalls; + info=rate+" byte/s with buffer size "+fSettings.getBufferSize(); + setTitle(info); + tDisplay=System.currentTimeMillis(); + } + n=0; + t0=System.currentTimeMillis(); + } + } while(line!=null); + } + private void sleep(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + private void setTitle(final String title) { + Display.getDefault().asyncExec(new Runnable(){ + public void run() { + fControl.setTerminalTitle(title); + }}); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestConnector.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestConnector.java new file mode 100644 index 00000000000..59a8121c2bf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestConnector.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [225853][api] Provide more default functionality in TerminalConnectorImpl + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.speedtest; + +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.Logger; +import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; + +public class SpeedTestConnector extends TerminalConnectorImpl { + final SpeedTestSettings fSettings=new SpeedTestSettings(); + InputStream fInputStream; + OutputStream fOutputStream; + SpeedTestConnection fConnection; + public SpeedTestConnector() { + } + synchronized public void connect(ITerminalControl control) { + super.connect(control); + fControl.setState(TerminalState.CONNECTING); + String file=fSettings.getInputFile(); + try { + fInputStream=new BufferedInputStream(new FileInputStream(file)); + } catch (FileNotFoundException e) { + disconnect(); + fControl.setMsg(file+": "+e.getLocalizedMessage()); + return; + } + fOutputStream=System.out; + fControl.setTerminalTitle(fSettings.getInputFile()); + fConnection=new SpeedTestConnection(fInputStream,fSettings,fControl); + fConnection.start(); + } + + synchronized public void doDisconnect() { + if(fConnection!=null){ + fConnection.interrupt(); + fConnection=null; + } + if (fInputStream != null) { + try { + fInputStream.close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + fInputStream=null; + if (fOutputStream != null) { + try { + fOutputStream.close(); + } catch (Exception exception) { + Logger.logException(exception); + } + } + fOutputStream=null; + } + synchronized public InputStream getInputStream() { + return fInputStream; + } + + synchronized public OutputStream getTerminalToRemoteStream() { + return fOutputStream; + } + + public String getSettingsSummary() { + return fSettings.getInputFile(); + } + + @Override + public void setDefaultSettings() { + fSettings.load(new NullSettingsStore()); + } + + public void load(ISettingsStore store) { + fSettings.load(store); + } + + public void save(ISettingsStore store) { + fSettings.save(store); + } + + public void setTerminalSize(int newWidth, int newHeight) { + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestSettings.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestSettings.java new file mode 100644 index 00000000000..821fa04ba4c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/speedtest/SpeedTestSettings.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.speedtest; + + +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +public class SpeedTestSettings { + String fInputFile=""; + String fBufferSize=""; + String fThrottle; + String getInputFile() { + return fInputFile; + } + public String getBufferSizeString() { + return getBufferSize()+""; + } + public void setBufferSizeString(String bufferSize) { + fBufferSize = bufferSize; + } + public int getBufferSize() { + try { + return Integer.parseInt(fBufferSize); + } catch(RuntimeException e) { + return 1024; + } + } + void setInputFile(String testFile) { + fInputFile = testFile; + } + public void load(ISettingsStore store) { + fInputFile=store.get("inputFile", ""); + fBufferSize=store.get("bufferSize", ""); + fThrottle=store.get("throttle", "0"); + } + public void save(ISettingsStore store) { + store.put("inputFile", fInputFile); + store.put("bufferSize", fBufferSize); + store.put("throttle", fThrottle); + } + public String getThrottleString() { + return fThrottle; + } + public int getThrottle() { + try { + return Integer.parseInt(fThrottle); + } catch(RuntimeException e) { + return 0; + } + } + public void setThrottleString(String throttle) { + fThrottle = throttle; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/Main.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/Main.java new file mode 100644 index 00000000000..73cefecc023 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/Main.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.terminalcanvas; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Shell; + +public class Main { + + /** + * @param args + */ + public static void main(String[] args) { + Display display = new Display (); + Shell shell = new Shell (display); + shell.setLayout(new FillLayout()); + new TerminalTextCanvas(shell,SWT.NONE); + shell.setSize (200, 150); + shell.open (); + while (!shell.isDisposed ()) { + if (!display.readAndDispatch ()) display.sleep (); + } + display.dispose (); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/Snippet48.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/Snippet48.java new file mode 100644 index 00000000000..f3a96c99ad3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/Snippet48.java @@ -0,0 +1,121 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.terminalcanvas; + + +/* + * Canvas example snippet: scroll an image (flicker free, no double buffering) + * + * For a list of all SWT example snippets see + * http://www.eclipse.org/swt/snippets/ + */ +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; +import org.eclipse.swt.widgets.Shell; + +public class Snippet48 { + +public static void main (String [] args) { + Display display = new Display (); + Shell shell = new Shell (display); + shell.setLayout(new FillLayout()); + Image originalImage = null; + FileDialog dialog = new FileDialog (shell, SWT.OPEN); + dialog.setText ("Open an image file or cancel"); + String string = dialog.open (); + if (string != null) { + originalImage = new Image (display, string); + } + final Image image = originalImage; + final Point origin = new Point (0, 0); + final Canvas canvas = new Canvas (shell, SWT.NO_BACKGROUND | + SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL); + final ScrollBar hBar = canvas.getHorizontalBar (); + hBar.addListener (SWT.Selection, new Listener () { + public void handleEvent (Event e) { + int hSelection = hBar.getSelection (); + int destX = -hSelection - origin.x; + Rectangle rect = image.getBounds (); + canvas.scroll (destX, 0, 0, 0, rect.width, rect.height, false); + origin.x = -hSelection; + } + }); + final ScrollBar vBar = canvas.getVerticalBar (); + vBar.addListener (SWT.Selection, new Listener () { + public void handleEvent (Event e) { + int vSelection = vBar.getSelection (); + int destY = -vSelection - origin.y; + Rectangle rect = image.getBounds (); + canvas.scroll (0, destY, 0, 0, rect.width, rect.height, false); + origin.y = -vSelection; + } + }); + canvas.addListener (SWT.Resize, new Listener () { + public void handleEvent (Event e) { + Rectangle rect = image.getBounds (); + Rectangle client = canvas.getClientArea (); + hBar.setMaximum (rect.width); + vBar.setMaximum (rect.height); + hBar.setThumb (Math.min (rect.width, client.width)); + vBar.setThumb (Math.min (rect.height, client.height)); + int hPage = rect.width - client.width; + int vPage = rect.height - client.height; + int hSelection = hBar.getSelection (); + int vSelection = vBar.getSelection (); + if (hSelection >= hPage) { + if (hPage <= 0) hSelection = 0; + origin.x = -hSelection; + } + if (vSelection >= vPage) { + if (vPage <= 0) vSelection = 0; + origin.y = -vSelection; + } + canvas.redraw (); + } + }); + canvas.addListener (SWT.Paint, new Listener () { + public void handleEvent (Event e) { + GC gc = e.gc; + gc.drawImage (image, origin.x, origin.y); + Rectangle rect = image.getBounds (); + Rectangle client = canvas.getClientArea (); + int marginWidth = client.width - rect.width; + if (marginWidth > 0) { + gc.fillRectangle (rect.width, 0, marginWidth, client.height); + } + int marginHeight = client.height - rect.height; + if (marginHeight > 0) { + gc.fillRectangle (0, rect.height, client.width, marginHeight); + } + } + }); + shell.setSize (200, 150); + shell.open (); + while (!shell.isDisposed ()) { + if (!display.readAndDispatch ()) display.sleep (); + } + originalImage.dispose(); + display.dispose (); +} + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/TerminalTextCanvas.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/TerminalTextCanvas.java new file mode 100644 index 00000000000..5027b2b3e80 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/TerminalTextCanvas.java @@ -0,0 +1,103 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.terminalcanvas; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; + +public class TerminalTextCanvas extends Canvas { + Image image; + Point origin = new Point (0, 0); + public TerminalTextCanvas(Composite parent, int style) { + super(parent, SWT.NO_BACKGROUND | + SWT.NO_REDRAW_RESIZE | SWT.V_SCROLL | SWT.H_SCROLL| style); + loadImage(parent); + + final ScrollBar hBar = getHorizontalBar (); + hBar.addListener (SWT.Selection, new Listener () { + public void handleEvent (Event e) { + int hSelection = hBar.getSelection (); + int destX = -hSelection - origin.x; + Rectangle rect = image.getBounds (); + scroll (destX, 0, 0, 0, rect.width, rect.height, false); + origin.x = -hSelection; + } + }); + final ScrollBar vBar = getVerticalBar (); + vBar.addListener (SWT.Selection, new Listener () { + public void handleEvent (Event e) { + int vSelection = vBar.getSelection (); + int destY = -vSelection - origin.y; + Rectangle rect = image.getBounds (); + scroll (0, destY, 0, 0, rect.width, rect.height, false); + origin.y = -vSelection; + } + }); + addListener (SWT.Resize, new Listener () { + public void handleEvent (Event e) { + Rectangle rect = image.getBounds (); + Rectangle client = getClientArea (); + hBar.setMaximum (rect.width); + vBar.setMaximum (rect.height); + hBar.setThumb (Math.min (rect.width, client.width)); + vBar.setThumb (Math.min (rect.height, client.height)); + int hPage = rect.width - client.width; + int vPage = rect.height - client.height; + int hSelection = hBar.getSelection (); + int vSelection = vBar.getSelection (); + if (hSelection >= hPage) { + if (hPage <= 0) hSelection = 0; + origin.x = -hSelection; + } + if (vSelection >= vPage) { + if (vPage <= 0) vSelection = 0; + origin.y = -vSelection; + } + redraw (); + } + }); + addListener (SWT.Paint, new Listener () { + public void handleEvent (Event e) { + GC gc = e.gc; + System.out.println(gc.getClipping()+" "+origin); + gc.drawImage (image, origin.x, origin.y); + Rectangle rect = image.getBounds (); + Rectangle client = getClientArea (); + int marginWidth = client.width - rect.width; + if (marginWidth > 0) { + gc.fillRectangle (rect.width, 0, marginWidth, client.height); + } + int marginHeight = client.height - rect.height; + if (marginHeight > 0) { + gc.fillRectangle (0, rect.height, client.width, marginHeight); + } + } + }); + } + private void loadImage(Composite parent) { + FileDialog dialog = new FileDialog (parent.getShell(), SWT.OPEN); + dialog.setText ("Open an image file or cancel"); + String string = dialog.open (); + if (string != null) { + image = new Image (getDisplay(), string); + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/VirtualCanvas.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/VirtualCanvas.java new file mode 100644 index 00000000000..461f544dfb9 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/terminalcanvas/VirtualCanvas.java @@ -0,0 +1,333 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.terminalcanvas; + + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Canvas; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.ScrollBar; + +/** + * A Canvas showing a virtual object. + * Virtual: the extent of the total canvas. + * Screen: the visible client area in the screen. + */ +public abstract class VirtualCanvas extends Canvas { + + private final Rectangle fVirtualBounds = new Rectangle(0,0,0,0); + private Rectangle fClientArea; + private GC fPaintGC=null; + public VirtualCanvas(Composite parent, int style) { + super(parent, style|SWT.NO_BACKGROUND|SWT.NO_REDRAW_RESIZE); + fPaintGC= new GC(this); + addListener(SWT.Paint, new Listener() { + public void handleEvent(Event event) { + paint(event.gc); + } + }); + addListener(SWT.Resize, new Listener() { + public void handleEvent(Event event) { + fClientArea=getClientArea(); + updateViewRectangle(); + } + }); + getVerticalBar().addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + scrollY((ScrollBar)e.widget); + postScrollEventHandling(e); + + } + + }); + getHorizontalBar().addListener(SWT.Selection, new Listener() { + public void handleEvent(Event e) { + scrollX((ScrollBar)e.widget); + postScrollEventHandling(e); + + } + }); + addDisposeListener(new DisposeListener(){ + public void widgetDisposed(DisposeEvent e) { + if(fPaintGC!=null){ + fPaintGC.dispose(); + fPaintGC=null; + } + } + + }); + } + public void setAutoSelect(boolean on) { + } + public boolean hasAutoSelect() { + return false; + } + public void doAutoSelect() { + } + + /** HACK: run an event loop if the scrollbar is dragged...*/ + private void postScrollEventHandling(Event e) { + if(true&&e.detail==SWT.DRAG) { + // TODO check if this is always ok??? + // used to process runnables while scrolling + // This fixes the update problems when scrolling! + // see: https://bugs.eclipse.org/bugs/show_bug.cgi?id=47582#5 + // TODO investigate: + // The alternative is to call redraw on the new visible area + // redraw(expose.x, expose.y, expose.width, expose.height, true); + + while (!getDisplay().isDisposed() && getDisplay().readAndDispatch()) { + // do nothing here... + } + } + } + + protected void scrollX(ScrollBar hBar) { + int hSelection = hBar.getSelection (); + int destX = -hSelection - fVirtualBounds.x; + fVirtualBounds.x = -hSelection; + scrollSmart(destX, 0); + updateViewRectangle(); + } + protected void scrollXDelta(int delta) { + getHorizontalBar().setSelection(-fVirtualBounds.x+delta); + scrollX(getHorizontalBar()); + } + + protected void scrollY(ScrollBar vBar) { + int vSelection = vBar.getSelection (); + int destY = -vSelection - fVirtualBounds.y; + fVirtualBounds.y = -vSelection; + scrollSmart(0,destY); + updateViewRectangle(); + + } + protected void scrollYDelta(int delta) { + getVerticalBar().setSelection(-fVirtualBounds.y+delta); + scrollY(getVerticalBar()); + } + + + private void scrollSmart(int deltaX, int deltaY) { + Rectangle rect = getBounds(); + scroll (deltaX, deltaY, 0, 0, rect.width, rect.height, false); + } + + protected void revealRect(Rectangle rect) { + Rectangle visibleRect=getScreenRectInVirtualSpace(); + // scroll the X part + int deltaX=0; + if(rect.x0||marginHeight>0){ + Color bg=getBackground(); + gc.setBackground(getBackgroundCanvasColor()); + if (marginWidth > 0) { + gc.fillRectangle (width, clipping.y, marginWidth, clipping.height); + } + if (marginHeight > 0) { + gc.fillRectangle (clipping.x, height, clipping.width, marginHeight); + } + gc.setBackground(bg); + } + } + /** + * @private + */ + protected boolean inClipping(Rectangle clipping, Rectangle r) { + // TODO check if this is OK in all cases (the <=!) + // + if(r.x+r.width<=clipping.x) + return false; + if(clipping.x+clipping.width<=r.x) + return false; + if(r.y+r.height<=clipping.y) + return false; + if(clipping.y+clipping.height<=r.y) + return false; + + return true; + } + /** + * @return the screen rect in virtual space (starting with (0,0)) + * of the visible screen. (x,y>=0) + */ + protected Rectangle getScreenRectInVirtualSpace() { + return new Rectangle(fClientArea.x-fVirtualBounds.x,fClientArea.y-fVirtualBounds.y,fClientArea.width,fClientArea.height); + } + /** + * @return the rect in virtual space (starting with (0,0)) + * of the visible screen. (x,y>=0) + */ + protected Rectangle getRectInVirtualSpace(Rectangle r) { + return new Rectangle(r.x-fVirtualBounds.x,r.y-fVirtualBounds.y,r.width,r.height); + } + + /** + * Sets the extend of the virtual dieplay ares + * @param width + * @param height + */ + protected void setVirtualExtend(int width, int height) { + fVirtualBounds.width=width; + fVirtualBounds.height=height; + updateScrollbars(); + updateViewRectangle(); + } + /** + * sets the scrolling origin. Also sets the scrollbars. + * Does NOT redraw! + * Use negative values (move the virtual origin to the top left + * to see something in the screen (which is located at (0,0)) + * @param x + * @param y + */ + protected void setVirtualOrigin(int x, int y) { + fVirtualBounds.x=x; + fVirtualBounds.y=y; + getHorizontalBar().setSelection(x); + getVerticalBar().setSelection(y); + updateViewRectangle(); + } + + /** + * @param x + * @return the virtual coordinate in scree space + */ + protected int virtualXtoScreen(int x) { + return x+fVirtualBounds.x; + } + protected int virtualYtoScreen(int y) { + return y+fVirtualBounds.y; + } + protected int screenXtoVirtual(int x) { + return x-fVirtualBounds.x; + } + protected int screenYtoVirtual(int y) { + return y-fVirtualBounds.y; + } + /** called when the viewed part is changing */ + private final Rectangle fViewRectangle=new Rectangle(0,0,0,0); + void updateViewRectangle() { + if( + fViewRectangle.x==-fVirtualBounds.x + && fViewRectangle.y==-fVirtualBounds.y + && fViewRectangle.width==fClientArea.width + && fViewRectangle.height==fClientArea.height + ) + return; + fViewRectangle.x=-fVirtualBounds.x; + fViewRectangle.y=-fVirtualBounds.y; + fViewRectangle.width=fClientArea.width; + fViewRectangle.height=fClientArea.height; + viewRectangleChanged(fViewRectangle.x,fViewRectangle.y,fViewRectangle.width,fViewRectangle.height); + } + protected Rectangle getViewRectangle() { + return fViewRectangle; + } + /** + * Called when the viewed part has changed. + * Override when you need this information.... + * Is only called if the values change! + * @param x visible in virtual space + * @param y visible in virtual space + * @param width + * @param height + */ + protected void viewRectangleChanged(int x, int y, int width, int height) { +// System.out.println(x+" "+y+" "+width+" "+height); + } + /** + * @private + */ + private void updateScrollbars() { + Point size= getSize(); + Rectangle clientArea= getClientArea(); + + ScrollBar horizontal= getHorizontalBar(); + if (fVirtualBounds.width <= clientArea.width) { + // TODO IMPORTANT in ScrollBar.setVisible comment out the line + // that checks 'isvisible' and returns (at the beginning) + horizontal.setVisible(false); + horizontal.setSelection(0); + } else { + horizontal.setPageIncrement(clientArea.width - horizontal.getIncrement()); + int max= fVirtualBounds.width + (size.x - clientArea.width); + horizontal.setMaximum(max); + horizontal.setThumb(size.x > max ? max : size.x); + horizontal.setVisible(true); + } + + ScrollBar vertical= getVerticalBar(); + if (fVirtualBounds.height <= clientArea.height) { + vertical.setVisible(false); + vertical.setSelection(0); + } else { + vertical.setPageIncrement(clientArea.height - vertical.getIncrement()); + int max= fVirtualBounds.height + (size.y - clientArea.height); + vertical.setMaximum(max); + vertical.setThumb(size.y > max ? max : size.y); + vertical.setVisible(true); + } + } +} + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/AbstractLineOrientedDataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/AbstractLineOrientedDataSource.java new file mode 100644 index 00000000000..82311f06f36 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/AbstractLineOrientedDataSource.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.Style; + +/** + * Adds line by line + * + */ +abstract class AbstractLineOrientedDataSource implements IDataSource { + abstract public char[] dataSource(); + abstract public Style getStyle(); + + abstract public void next(); + + public int step(ITerminalTextData terminal) { + next(); + char[] chars=dataSource(); + Style style= getStyle(); + int len; + // keep the synchronized block short! + synchronized (terminal) { + terminal.addLine(); + len=Math.min(terminal.getWidth(),chars.length); + int line=terminal.getHeight()-1; + terminal.setChars(line, 0, chars, 0, len, style); + terminal.setCursorLine(line); + terminal.setCursorColumn(len-1); + } + return len; + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/DataReader.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/DataReader.java new file mode 100644 index 00000000000..854509a1ecd --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/DataReader.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import org.eclipse.tm.terminal.model.ITerminalTextData; + +class DataReader implements Runnable { + final Thread fThread; + final IDataSource fDataSource; + final ITerminalTextData fTerminal; + volatile boolean fStart; + volatile boolean fStop; + volatile int fThrottleTime; + final IStatus fStatus; + final String fName; + DataReader(String name, ITerminalTextData terminal, IDataSource dataSource, IStatus status) { + fStatus=status; + fName=name; + fTerminal=terminal; + fDataSource=dataSource; + fThread=new Thread(this,name); + fThread.setDaemon(true); + fThread.start(); + } + public void run() { + long t0=System.currentTimeMillis()-1; + long c=0; + int lines=0; + while(!Thread.interrupted()) { + while(!fStart || fStop) { + sleep(1); + } + if(fThrottleTime>0) + sleep(fThrottleTime); + // synchronize because we have to be sure the size does not change while + // we add lines + int len=fDataSource.step(fTerminal); + // keep the synchronized block short! + c+=len; + lines++; + if((fThrottleTime>0 || (lines%100==0))&&(System.currentTimeMillis()-t0)>1000) { + long t=System.currentTimeMillis()-t0; + final String s=(c*1000)/(t*1024)+"kb/s " + (lines*1000)/t+"lines/sec "+(c*1000*8)/t+" bits/s "; + fStatus.setStatus(s); + lines=0; + t0=System.currentTimeMillis(); + c=0; + } + } + } + public int getThrottleTime() { + return fThrottleTime; + } + public void setThrottleTime(int throttleTime) { + fThrottleTime = throttleTime; + } + private void sleep(int ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + public boolean isStart() { + return fStart; + } + public void setStart(boolean start) { + fStart = start; + } + public String getName() { + return fName; + } + public boolean isStop() { + return fStop; + } + public void setStop(boolean stop) { + fStop = stop; + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/FastDataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/FastDataSource.java new file mode 100644 index 00000000000..ce4ac180794 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/FastDataSource.java @@ -0,0 +1,35 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import org.eclipse.tm.terminal.model.Style; + +final class FastDataSource extends AbstractLineOrientedDataSource { + char lines[][]=new char[][]{ + "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 ".toCharArray(), + "abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi abcdefghi ".toCharArray(), + }; + + + int pos; + + public char[] dataSource() { + return lines[pos%lines.length]; + } + + public Style getStyle() { + return null; + } + + public void next() { + pos++; + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/FileDataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/FileDataSource.java new file mode 100644 index 00000000000..7680394e6a2 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/FileDataSource.java @@ -0,0 +1,72 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; + +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +/** + * Reads the file in an infinite loop. + * Makes lines containing 'x' bold. + * + */ +final class FileDataSource extends AbstractLineOrientedDataSource { + private final String fFile; + + BufferedReader reader; + + String line; + + Style style; + + Style styleNormal=Style.getStyle(StyleColor.getStyleColor("black"),StyleColor.getStyleColor("white")); + + Style styleBold=styleNormal.setBold(true); + + FileDataSource(String file) { + fFile = file; + } + + public char[] dataSource() { + return line.toCharArray(); + } + + public Style getStyle() { + return style; + } + + public void next() { + try { + if(reader==null) + reader = new BufferedReader(new FileReader(fFile)); + line=reader.readLine(); + if(line==null) { + reader.close(); + reader=null; + // reopen the file + next(); + return; + } + if(line.lastIndexOf('x')>0) + style=styleBold; + else + style=styleNormal; + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/IDataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/IDataSource.java new file mode 100644 index 00000000000..44a2bf6400e --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/IDataSource.java @@ -0,0 +1,21 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import org.eclipse.tm.terminal.model.ITerminalTextData; + +interface IDataSource { + /** + * @param terminal + * @return number of characters changed + */ + int step(ITerminalTextData terminal); +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/IStatus.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/IStatus.java new file mode 100644 index 00000000000..351023697a6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/IStatus.java @@ -0,0 +1,15 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +public interface IStatus { + void setStatus(String message); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/LineCountingDataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/LineCountingDataSource.java new file mode 100644 index 00000000000..8be77cb2c4f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/LineCountingDataSource.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +final class LineCountingDataSource extends AbstractLineOrientedDataSource { + Style styleNormal=Style.getStyle(StyleColor.getStyleColor("black"),StyleColor.getStyleColor("red")); + + Style styles[]=new Style[] { + styleNormal, + styleNormal.setBold(true), + styleNormal.setForground("blue"), + styleNormal.setForground("yellow"), + styleNormal.setBold(true).setUnderline(true), + styleNormal.setReverse(true), + styleNormal.setReverse(true).setBold(true), + styleNormal.setReverse(true).setUnderline(true) + }; + + int pos; + + public char[] dataSource() { + return (pos+" 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789").toCharArray(); + } + + public Style getStyle() { + return styles[pos%styles.length]; + } + + public void next() { + pos++; + } +} \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/RandomDataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/RandomDataSource.java new file mode 100644 index 00000000000..5e797f10808 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/RandomDataSource.java @@ -0,0 +1,49 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import java.util.Random; + +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.Style; +import org.eclipse.tm.terminal.model.StyleColor; + +public class RandomDataSource implements IDataSource { + Random fRandom=new Random(); + Style styleNormal=Style.getStyle(StyleColor.getStyleColor("black"),StyleColor.getStyleColor("green")); + Style styles[]=new Style[] { + styleNormal, + styleNormal.setBold(true), + styleNormal.setForground("red"), + styleNormal.setForground("yellow"), + styleNormal.setBold(true).setUnderline(true), + styleNormal.setReverse(true), + styleNormal.setReverse(true).setBold(true), + styleNormal.setReverse(true).setUnderline(true) + }; + + public int step(ITerminalTextData terminal) { + int N=fRandom.nextInt(1000); + int h=terminal.getHeight(); + int w=terminal.getWidth(); + synchronized (terminal) { + for (int i = 0; i < N; i++) { + int line=fRandom.nextInt(h); + int col=fRandom.nextInt(w); + char c=(char)('A'+fRandom.nextInt('z'-'A')); + Style style=styles[fRandom.nextInt(styles.length)]; + terminal.setChar(line, col, c, style); + } + } + return N; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/TerminalTextUITest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/TerminalTextUITest.java new file mode 100644 index 00000000000..284d2c859d1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/TerminalTextUITest.java @@ -0,0 +1,253 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +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.layout.RowData; +import org.eclipse.swt.layout.RowLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.internal.terminal.textcanvas.ITextCanvasModel; +import org.eclipse.tm.internal.terminal.textcanvas.PollingTextCanvasModel; +import org.eclipse.tm.internal.terminal.textcanvas.TextCanvas; +import org.eclipse.tm.internal.terminal.textcanvas.TextLineRenderer; +import org.eclipse.tm.terminal.model.ITerminalTextData; +import org.eclipse.tm.terminal.model.ITerminalTextDataSnapshot; +import org.eclipse.tm.terminal.model.TerminalTextDataFactory; + +/** + * adjust columns when table gets resized.... + * + */ +public class TerminalTextUITest { + static TextCanvas fgTextCanvas; + static ITextCanvasModel fgModel; + static ITerminalTextData fTerminalModel; + static Label fStatusLabel; + static volatile int fHeight; + static volatile int fWidth; + static DataReader fDataReader; + static List fDataReaders=new ArrayList(); + private static Text heightText; + static class Status implements IStatus { + public void setStatus(final String s) { + if(!fStatusLabel.isDisposed()) + Display.getDefault().asyncExec(new Runnable(){ + public void run() { + if(!fStatusLabel.isDisposed()) + fStatusLabel.setText(s); + }}); + } + + } + public static void main(String[] args) { + Display display = new Display(); + Shell shell = new Shell(display); + shell.setLayout(new GridLayout()); + Composite composite=new Composite(shell, SWT.NONE); + composite.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + RowLayout layout = new RowLayout(SWT.HORIZONTAL); + layout.wrap = true; + layout.fill = false; + fTerminalModel=TerminalTextDataFactory.makeTerminalTextData(); + fHeight=24; + fWidth=80; + fTerminalModel.setDimensions(fHeight, fWidth); + fTerminalModel.setMaxHeight(fHeight); + ITerminalTextDataSnapshot snapshot=fTerminalModel.makeSnapshot(); + // TODO how to get the initial size correctly! + snapshot.updateSnapshot(false); + fgModel=new PollingTextCanvasModel(snapshot); + fgTextCanvas=new TextCanvas(shell,fgModel, SWT.NONE,new TextLineRenderer(fgTextCanvas,fgModel)); + fgTextCanvas.setLayoutData(new GridData(GridData.FILL_BOTH)); + + + composite.setLayout(layout); + addAutorevealCursorButton(composite); + Text maxHeightText = addMaxHeightInput(composite); + addHeightInput(composite, maxHeightText); + addWidthText(composite); + Text throttleText = addThrottleText(composite); + + IStatus status=new Status(); + DataReader reader=new DataReader("Line Count",fTerminalModel,new LineCountingDataSource(),status); + addDataReader(composite, reader); + reader=new DataReader("Fast",fTerminalModel,new FastDataSource(),status); + addDataReader(composite, reader); + reader=new DataReader("Random",fTerminalModel,new RandomDataSource(),status); + addDataReader(composite, reader); + for (int i = 0; i < args.length; i++) { + File file=new File(args[i]); + reader=new DataReader(file.getName(),fTerminalModel,new VT100DataSource(args[i]),status); + addDataReader(composite, reader); + } + addStopAllButton(composite, reader); + + fStatusLabel=new Label(shell,SWT.NONE); + fStatusLabel.setLayoutData(new GridData(250,15)); + throttleText.setText("100"); + setThrottleForAll(100); + + if(args.length==0) + addLabel(composite, "[Files can be added via commandline]"); + shell.setSize(600,300); + shell.open(); + while (!shell.isDisposed()) { + if (!display.readAndDispatch()) + display.sleep(); + } + display.dispose(); + } + private static Text addMaxHeightInput(Composite composite) { + addLabel(composite, "maxHeight:"); + final Text maxHeightText=new Text(composite,SWT.BORDER); + setLayoutData(maxHeightText,30); + maxHeightText.addModifyListener(new ModifyListener(){ + public void modifyText(ModifyEvent e) { + synchronized (fTerminalModel) { + int height=textToInt(maxHeightText); + if(height<1) + return; + if(fTerminalModel.getHeight()>height) { + fTerminalModel.scroll(0, fTerminalModel.getHeight(), height-fTerminalModel.getHeight()); + fTerminalModel.setDimensions(height,fTerminalModel.getWidth()); + heightText.setText(height+""); + } + fTerminalModel.setMaxHeight(height); + } + } + }); + maxHeightText.setText(fHeight+""); + return maxHeightText; + } + private static void addHeightInput(Composite composite, final Text maxHeightText) { + addLabel(composite,"heigth:"); + heightText=new Text(composite,SWT.BORDER); + setLayoutData(heightText,30); + heightText.addModifyListener(new ModifyListener(){ + public void modifyText(ModifyEvent e) { + synchronized (fTerminalModel) { + int height=textToInt(heightText); + if(height<1) + return; + maxHeightText.setText(""+height); + fTerminalModel.setDimensions(height,fTerminalModel.getWidth()); + fTerminalModel.setMaxHeight(height); + } + } + }); + heightText.setText(fHeight+""); + } + private static Text addWidthText(Composite composite) { + addLabel(composite,"width:"); + final Text widthText=new Text(composite,SWT.BORDER); + setLayoutData(widthText,30); + widthText.addModifyListener(new ModifyListener(){ + public void modifyText(ModifyEvent e) { + synchronized (fTerminalModel) { + int width=textToInt(widthText); + if(width>1) + fTerminalModel.setDimensions(fTerminalModel.getHeight(), width); + } + } + }); + widthText.setText(fWidth+""); + return widthText; + } + private static Text addThrottleText(Composite composite) { + addLabel(composite,"throttle:"); + final Text throttleText=new Text(composite,SWT.BORDER); + setLayoutData(throttleText,30); + throttleText.addModifyListener(new ModifyListener(){ + public void modifyText(ModifyEvent e) { + synchronized (fTerminalModel) { + int throttle=textToInt(throttleText); + setThrottleForAll(throttle); + } + }}); + return throttleText; + } + private static void addStopAllButton(Composite composite, DataReader reader) { + final Button stopAllButton=new Button(composite,SWT.CHECK); + stopAllButton.setText("Stop ALL"); + stopAllButton.addSelectionListener(new SelectionAdapter(){ + + public void widgetSelected(SelectionEvent e) { + boolean stop=stopAllButton.getSelection(); + for (Iterator iterator = fDataReaders.iterator(); iterator.hasNext();) { + DataReader reader = (DataReader) iterator.next(); + reader.setStop(stop); + + }}}); + stopAllButton.setSelection(reader.isStart()); + } + private static void addAutorevealCursorButton(Composite composite) { + final Button button=new Button(composite,SWT.CHECK); + button.setText("ScrollLock"); + button.addSelectionListener(new SelectionAdapter(){ + public void widgetSelected(SelectionEvent e) { + boolean scrollLock=button.getSelection(); + fgTextCanvas.setScrollLock(scrollLock); + } + }); + button.setSelection(fgTextCanvas.isScrollLock()); + } + private static void addLabel(Composite composite,String message) { + Label label; + label=new Label(composite, SWT.NONE); + label.setText(message); + } + private static void addDataReader(Composite composite, final DataReader reader) { + fDataReaders.add(reader); + final Button button=new Button(composite,SWT.CHECK); + button.setText(reader.getName()); + button.addSelectionListener(new SelectionAdapter(){ + + public void widgetSelected(SelectionEvent e) { + reader.setStart(button.getSelection()); + }}); + button.setSelection(reader.isStart()); + + } + static private void setThrottleForAll(int throttle) { + for (Iterator iterator = fDataReaders.iterator(); iterator.hasNext();) { + DataReader reader = (DataReader) iterator.next(); + reader.setThrottleTime(throttle); + } + } + static void setLayoutData(Control c,int width) { + c.setLayoutData(new RowData(width,-1)); + } + static int textToInt(Text text) { + try { + return Integer.valueOf(text.getText()).intValue(); + } catch (Exception ex) { + return 0; + } + } +} + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/VT100DataSource.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/VT100DataSource.java new file mode 100644 index 00000000000..589e9542f65 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/test/ui/VT100DataSource.java @@ -0,0 +1,133 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + * Martin Oberhuber (Wind River) - [204796] Terminal should allow setting the encoding to use + * Anton Leherbauer (Wind River) - [458398] Add support for normal/application cursor keys mode + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.test.ui; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.Reader; +import java.io.UnsupportedEncodingException; + +import org.eclipse.tm.internal.terminal.control.impl.ITerminalControlForText; +import org.eclipse.tm.internal.terminal.emulator.VT100Emulator; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.model.ITerminalTextData; + +/** + * Reads the file in an infinite loop. + * Makes lines containing 'x' bold. + * + */ +final class VT100DataSource implements IDataSource { + VT100Emulator fEmulator; + volatile int fAvailable; + volatile int fRead; + private final String fFile; + + VT100DataSource(String file) { + fFile=file; + } + class InfiniteFileInputStream extends InputStream { + public InfiniteFileInputStream() { + try { + fInputStream=new FileInputStream(fFile); + } catch (FileNotFoundException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + public int available() throws IOException { + return fAvailable; + } + private InputStream fInputStream; + public int read() throws IOException { + throw new IOException(); + } + public int read(byte[] b, int off, int len) throws IOException { + while(fAvailable==0) { + try { + Thread.sleep(1); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } + len=fAvailable; + int n=fInputStream.read(b, off, len); + if(n<=0) { + fInputStream.close(); + fInputStream=new FileInputStream(fFile); + n=fInputStream.read(b, off, len); + } + fAvailable-=n; + return n; + } + + } + void init(ITerminalTextData terminal) { + final Reader reader; + try { + reader = new InputStreamReader(new InfiniteFileInputStream(), "ISO-8859-1"); //$NON-NLS-1$ + } catch (UnsupportedEncodingException e) { + throw new RuntimeException(e); + } + fEmulator=new VT100Emulator(terminal,new ITerminalControlForText() { + + public void disconnectTerminal() { + // TODO Auto-generated method stub + + } + + public OutputStream getOutputStream() { + return new ByteArrayOutputStream(); + } + + public TerminalState getState() { + return TerminalState.CONNECTED; + } + + public ITerminalConnector getTerminalConnector() { + return null; + } + + public void setState(TerminalState state) { + } + + public void setTerminalTitle(String title) { + } + + public void enableApplicationCursorKeys(boolean enable) { + } + }, reader); + } + public int step(ITerminalTextData terminal) { + synchronized(terminal) { + if(fEmulator==null) { + init(terminal); +// fEmulator.setDimensions(48, 132); + fEmulator.setDimensions(24, 80); + fEmulator.setCrAfterNewLine(true); + + } + fAvailable=80; + fEmulator.processText(); + } + return 80; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/textcanvas/PipedInputStreamPerformanceTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/textcanvas/PipedInputStreamPerformanceTest.java new file mode 100644 index 00000000000..583059eae09 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/textcanvas/PipedInputStreamPerformanceTest.java @@ -0,0 +1,32 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +import java.io.OutputStream; + +public class PipedInputStreamPerformanceTest { + + /** + * @param args + * @throws InterruptedException + */ + public static void main(String[] args) throws InterruptedException { + runPerformanceTest(); + runPerformanceTest(); + } + + private static void runPerformanceTest() throws InterruptedException { + PipedInputStream in=new PipedInputStream(1024); + OutputStream out=in.getOutputStream(); + PipedStreamTest.runPipe("",in, out,100); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/textcanvas/PipedStreamTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/textcanvas/PipedStreamTest.java new file mode 100644 index 00000000000..d937ae2be17 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/internal/terminal/textcanvas/PipedStreamTest.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.internal.terminal.textcanvas; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + + +class PipedStreamTest { + static class ReadThread extends Thread implements Runnable { + + InputStream pi = null; + + OutputStream po = null; + + ReadThread(String process, InputStream pi, OutputStream po) { + this.pi = pi; + this.po = po; + setDaemon(true); + } + + public void run() { + byte[] buffer = new byte[2048]; + int bytes_read; + try { + for (;;) { + bytes_read = pi.read(buffer); + if (bytes_read == -1) { + po.close(); + pi.close(); + return; + } + po.write(buffer, 0, bytes_read); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + } + static class FakeInputStream extends InputStream { + int N; + FakeInputStream(int n) { + N=n; + } + public int read(byte[] b, int off, int len) throws IOException { + if(N==0) + return -1; + int n=Math.min(len,N); + for (int i = off; i < off+n; i++) { + b[i]='x'; + } + N-=n; + return n; + } + public int read() throws IOException { + throw new UnsupportedOperationException(); + } + /* + * available has to be implemented! + */ + public int available() throws IOException { + return N; + } + } + static class FakeOutputStream extends OutputStream { + long N; + public void write(int b) throws IOException { + throw new UnsupportedOperationException(); + } + public void write(byte[] b, int off, int len) throws IOException { + N+=len; + } + } + public static void main(String[] args) throws IOException, InterruptedException { + while(true) { + runSunTest(); + runMyTest(); + } + } + private static void runSunTest() throws IOException, InterruptedException { + java.io.PipedInputStream in = new java.io.PipedInputStream(); + OutputStream out = new java.io.PipedOutputStream(in); + runPipe("Sun ",in, out,10); + } + private static void runMyTest() throws IOException, InterruptedException { + PipedInputStream in=new PipedInputStream(4*1024); + OutputStream out=in.getOutputStream(); + runPipe("My ",in, out,99); + } + public static void runPipe(String what,InputStream writeIn, OutputStream readOut,int N) throws InterruptedException { + FakeInputStream in=new FakeInputStream(N*1000*1000); + FakeOutputStream out=new FakeOutputStream(); + ReadThread rt = new ReadThread("reader", in , readOut); + ReadThread wt = new ReadThread("writer", writeIn, out); + long t0=System.currentTimeMillis(); + rt.start(); + wt.start(); + wt.join(); + long t=System.currentTimeMillis(); + long n=out.N; + System.out.println(what+n + " byte in " +(t-t0)+" ms -> "+(1000*n)/((t-t0+1)*1024)+" kb/sec"); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/AllTests.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/AllTests.java new file mode 100644 index 00000000000..35356ad0240 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/AllTests.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Public Terminal Model test cases. + * Runs in internal model package to allow access to default visible items. + */ +public class AllTests extends TestCase { + public AllTests() { + super(null); + } + + public AllTests(String name) { + super(name); + } + + public static Test suite() { + TestSuite suite = new TestSuite(AllTests.class.getName()); + suite.addTestSuite(StyleColorTest.class); + suite.addTestSuite(StyleTest.class); + return suite; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/StyleColorTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/StyleColorTest.java new file mode 100644 index 00000000000..5c5784f4623 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/StyleColorTest.java @@ -0,0 +1,36 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +import junit.framework.TestCase; + +public class StyleColorTest extends TestCase { + + + public void testEqualsObject() { + assertEquals(StyleColor.getStyleColor("foo"),StyleColor.getStyleColor("foo")); + assertFalse(StyleColor.getStyleColor("foox").equals(StyleColor.getStyleColor("foo"))); + } + + public void testSameObject() { + assertSame(StyleColor.getStyleColor("foo"),StyleColor.getStyleColor("foo")); + assertNotSame(StyleColor.getStyleColor("foox"),StyleColor.getStyleColor("foo")); + } + + public void testToString() { + assertEquals("xxx", StyleColor.getStyleColor("xxx").toString()); + } + + public void testGetName() { + assertEquals("xxx", StyleColor.getStyleColor("xxx").getName()); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/StyleTest.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/StyleTest.java new file mode 100644 index 00000000000..b61de0c2c33 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/model/StyleTest.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2007, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * Contributors: + * Michael Scharf (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.model; + +import junit.framework.TestCase; + +public class StyleTest extends TestCase { + final StyleColor c1=StyleColor.getStyleColor("c1"); + final StyleColor c2=StyleColor.getStyleColor("c2"); + final StyleColor c3=StyleColor.getStyleColor("c3"); + + public void testGetStyle() { + Style s1=Style.getStyle(c1, c2, true, false, true, false); + Style s2=Style.getStyle(c1, c2, true, false, true, false); + assertEquals(s1,s2); + assertSame(s1,s2); + s1=s1.setBlink(!s1.isBlink()); + assertNotSame(s1,s2); + assertFalse(s1.equals(s2)); + s1=s1.setBlink(!s1.isBlink()); + assertSame(s1,s2); + } + + public void testSetForground() { + Style s1=Style.getStyle(c1, c2, true, false, true, false); + Style s2=s1; + s2=s1.setForground(c3); + assertNotSame(s1,s2); + assertFalse(s1.equals(s2)); + assertSame(s2.getForground(), c3); + assertSame(s1.getForground(), c1); + assertSame(s1.getBackground(), c2); + assertSame(s2.getBackground(), c2); + s2=s2.setForground(c1); + assertSame(s1, s2); + } + + public void testSetBackground() { + Style s1=Style.getStyle(c1, c2, true, false, true, false); + Style s2=s1; + s2=s1.setBackground(c3); + assertNotSame(s1,s2); + assertFalse(s1.equals(s2)); + assertSame(s2.getForground(), c1); + assertSame(s1.getForground(), c1); + assertSame(s1.getBackground(), c2); + assertSame(s2.getBackground(), c3); + s2=s2.setBackground(c2); + assertSame(s1, s2); + } + + public void testSetBold() { + Style s1=getDefaultStyle(); + Style s2=s1; + assertSame(s1,s2); + assertFalse(s2.isBold()); + s2=s2.setBold(true); + assertNotSame(s1,s2); + assertTrue(s2.isBold()); + s2=s2.setBold(false); + assertSame(s1,s2); + assertFalse(s2.isBold()); + } + + public void testSetBlink() { + Style s1=getDefaultStyle(); + Style s2=s1; + assertSame(s1,s2); + assertFalse(s2.isBlink()); + s2=s2.setBlink(true); + assertNotSame(s1,s2); + assertTrue(s2.isBlink()); + s2=s2.setBlink(false); + assertSame(s1,s2); + assertFalse(s2.isBlink()); + } + + public void testSetUnderline() { + Style s1=getDefaultStyle(); + Style s2=s1; + assertSame(s1,s2); + assertFalse(s2.isUnderline()); + s2=s2.setUnderline(true); + assertNotSame(s1,s2); + assertTrue(s2.isUnderline()); + s2=s2.setUnderline(false); + assertSame(s1,s2); + assertFalse(s2.isUnderline()); + } + + public void testSetReverse() { + Style s1=getDefaultStyle(); + Style s2=s1; + assertSame(s1,s2); + assertFalse(s2.isReverse()); + s2=s2.setReverse(true); + assertNotSame(s1,s2); + assertTrue(s2.isReverse()); + s2=s2.setReverse(false); + assertSame(s1,s2); + assertFalse(s2.isReverse()); + } + + private Style getDefaultStyle() { + return Style.getStyle(c1, c2, false, false, false, false); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/test/AutomatedPluginTests.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/test/AutomatedPluginTests.java new file mode 100644 index 00000000000..a2d7c7a2402 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/test/AutomatedPluginTests.java @@ -0,0 +1,39 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ + +package org.eclipse.tm.terminal.test; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Master Test Suite to run all Terminal plug-in tests. + */ +public class AutomatedPluginTests extends TestCase { + /** + * Call each AllTests class from each of the test packages. + */ + public static Test suite() { + TestSuite suite = new TestSuite(AutomatedPluginTests.class.getName()); + //These tests require Eclipse Platform to be up + suite.addTestSuite(org.eclipse.tm.internal.terminal.connector.TerminalConnectorPluginTest.class); + suite.addTestSuite(org.eclipse.tm.internal.terminal.connector.TerminalConnectorFactoryTest.class); + + //These tests must run as plain JUnit because they require access + //to "package" protected methods + //suite.addTest(AutomatedTests.suite()); + return suite; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/test/AutomatedTests.java b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/test/AutomatedTests.java new file mode 100644 index 00000000000..634268b7227 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/src/org/eclipse/tm/terminal/test/AutomatedTests.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2008, 2018 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 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Martin Oberhuber (Wind River) - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.test; + +import junit.framework.Test; +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Master test suite to run all terminal unit tests. + */ +public class AutomatedTests extends TestCase { + + public static final String PI_TERMINAL_TESTS = "org.eclipse.tm.terminal.test"; //$NON-NLS-1$ + + public AutomatedTests() { + super(null); + } + + public AutomatedTests(String name) { + super(name); + } + + /** + * Call each AllTests class from each of the test packages. + */ + public static Test suite() { + TestSuite suite = new TestSuite(AutomatedTests.class.getName()); + suite.addTest(org.eclipse.tm.internal.terminal.emulator.AllTests.suite()); + suite.addTest(org.eclipse.tm.internal.terminal.model.AllTests.suite()); + suite.addTest(org.eclipse.tm.terminal.model.AllTests.suite()); + suite.addTestSuite(org.eclipse.tm.internal.terminal.connector.TerminalConnectorTest.class); + suite.addTestSuite(org.eclipse.tm.internal.terminal.connector.TerminalToRemoteInjectionOutputStreamTest.class); + return suite; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal All Unit Tests.launch b/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal All Unit Tests.launch new file mode 100644 index 00000000000..fd2e3ebb9d4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal All Unit Tests.launch @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal AutomatedTests.launch b/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal AutomatedTests.launch new file mode 100644 index 00000000000..a8d7a4e206d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal AutomatedTests.launch @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal Plugin Tests.launch b/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal Plugin Tests.launch new file mode 100644 index 00000000000..0872cc461c3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.test/teamConfig/Terminal Plugin Tests.launch @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.test/tm32.png b/terminal/plugins/org.eclipse.tm.terminal.test/tm32.png new file mode 100644 index 00000000000..3077b1220dd Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.test/tm32.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.classpath b/terminal/plugins/org.eclipse.tm.terminal.view.core/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.view.core/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.options b/terminal/plugins/org.eclipse.tm.terminal.view.core/.options new file mode 100644 index 00000000000..a0a2c87a3c7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.options @@ -0,0 +1 @@ +org.eclipse.tm.terminal.view.core/debugmode = 0 diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.project b/terminal/plugins/org.eclipse.tm.terminal.view.core/.project new file mode 100644 index 00000000000..f6e4e7e96a0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.project @@ -0,0 +1,45 @@ + + + org.eclipse.tm.terminal.view.core + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + + + 1329501981620 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..7fc81751be8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,380 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=disabled +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore +org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull +org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault +org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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.nonnullParameterAnnotationDropped=warning +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error +org.eclipse.jdt.core.compiler.problem.nullReference=warning +org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=disabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.view.core/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..2c51f76c09d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/META-INF/MANIFEST.MF @@ -0,0 +1,21 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.view.core;singleton:=true +Bundle-Version: 4.5.100.qualifier +Bundle-Activator: org.eclipse.tm.terminal.view.core.activator.CoreBundleActivator +Bundle-Vendor: %providerName +Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.runtime;bundle-version="3.8.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.view.core, + org.eclipse.tm.terminal.view.core.activator;x-internal:=true, + org.eclipse.tm.terminal.view.core.interfaces, + org.eclipse.tm.terminal.view.core.interfaces.constants, + org.eclipse.tm.terminal.view.core.internal;x-internal:=true, + org.eclipse.tm.terminal.view.core.nls;x-internal:=true, + org.eclipse.tm.terminal.view.core.preferences, + org.eclipse.tm.terminal.view.core.tracing, + org.eclipse.tm.terminal.view.core.utils diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/about.html b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

            About This Content

            + +

            May 24, 2012

            +

            License

            + +

            The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

            + +

            If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

            + + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/about.ini b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.ini new file mode 100644 index 00000000000..3adc27ab587 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.ini @@ -0,0 +1,27 @@ +# about.ini +# contains information about a feature +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# "%key" are externalized strings defined in about.properties +# This file does not need to be translated. + +# Property "aboutText" contains blurb for "About" dialog (translated) +aboutText=%blurb + +# Property "windowImage" contains path to window icon (16x16) +# needed for primary features only + +# Property "featureImage" contains path to feature image (32x32) +featureImage=tm32.png + +# Property "aboutImage" contains path to product image (500x330 or 115x164) +# needed for primary features only + +# Property "appName" contains name of the application (not translated) +# needed for primary features only + +# Property "welcomePage" contains path to welcome page (special XML-based format) +# optional + +# Property "welcomePerspective" contains the id of the perspective in which the +# welcome page is to be opened. +# optional \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/about.mappings b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.mappings new file mode 100644 index 00000000000..bddaab43109 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.mappings @@ -0,0 +1,6 @@ +# about.mappings +# contains fill-ins for about.properties +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# This file does not need to be translated. + +0=@build@ \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/about.properties b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.properties new file mode 100644 index 00000000000..1d2b73c9510 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/about.properties @@ -0,0 +1,24 @@ +################################################################################ +# Copyright (c) 2006, 2018 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 2.0 +# which accompanies this distribution, and is available at +# https://www.eclipse.org/legal/epl-2.0/ +# +# Contributors: +# Martin Oberhuber - initial API and implementation +################################################################################ +# about.properties +# contains externalized strings for about.ini +# java.io.Properties file (ISO 8859-1 with "\" escapes) +# fill-ins are supplied by about.mappings +# This file should be translated. +# +# Do not translate any values surrounded by {} + +blurb=TM Terminal\n\ +\n\ +Version: {featureVersion}\n\ +\n\ +(c) Copyright Wind River Systems, Inc. and others 2011, 2016. All rights reserved.\n\ +Visit http://marketplace.eclipse.org/content/tm-terminal diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/build.properties b/terminal/plugins/org.eclipse.tm.terminal.view.core/build.properties new file mode 100644 index 00000000000..9ddb6f11abb --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/build.properties @@ -0,0 +1,22 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + about.html,\ + plugin.xml,\ + about.ini,\ + about.mappings,\ + about.properties,\ + tm32.png diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.view.core/plugin.properties new file mode 100644 index 00000000000..c58e818ef94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/plugin.properties @@ -0,0 +1,16 @@ +################################################################################## +# Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal View Core +providerName = Eclipse.org - Target Management + +ExtensionPoint.contextPropertiesProviders = Terminal Context Properties Providers diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.view.core/plugin.xml new file mode 100644 index 00000000000..4cb8069caee --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/plugin.xml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.view.core/pom.xml new file mode 100644 index 00000000000..0e4856a9fd6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/pom.xml @@ -0,0 +1,26 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.view.core + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/schema/contextPropertiesProviders.exsd b/terminal/plugins/org.eclipse.tm.terminal.view.core/schema/contextPropertiesProviders.exsd new file mode 100644 index 00000000000..3a9b909701d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/schema/contextPropertiesProviders.exsd @@ -0,0 +1,130 @@ + + + + + + + + + This extension point is used to contribute terminal context properties providers. The context properties provider allows querying desired properties for a given context. +<p> +The terminal context is passed in as default variable to the enablement expression evaluation. The terminal context is not expected to be iteratable or countable. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Declares a terminal context properties provider contribution. + + + + + + + + + + The class that implements <code>org.eclipse.tm.terminal.view.core.interfaces.ITerminalContextPropertiesProvider</code>. + + + + + + + + + + + + + + + TM Terminal 4.0.0 + + + + + + + + + This is an example of the extension point usage: +<p> +<pre><code> + <extension point="org.eclipse.tm.terminal.view.core.contextPropertiesProviders"> + <contextPropertiesProvider + class="com.my.contribution.MyContextPropertiesProviderImpl"> + </contextPropertiesProvider> + </extension> +</code></pre> + + + + + + + + + The provider of a terminal context properties provider must implement <samp>org.eclipse.tm.terminal.view.core.interfaces.ITerminalContextPropertiesProvider</samp>. + + + + + + + + + + Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is +available at https://www.eclipse.org/legal/epl-2.0/ + + SPDX-License-Identifier: EPL-2.0 + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/TerminalContextPropertiesProviderFactory.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/TerminalContextPropertiesProviderFactory.java new file mode 100644 index 00000000000..20414a4a846 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/TerminalContextPropertiesProviderFactory.java @@ -0,0 +1,230 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.EvaluationResult; +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.ExpressionConverter; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.terminal.view.core.activator.CoreBundleActivator; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalContextPropertiesProvider; +import org.eclipse.tm.terminal.view.core.nls.Messages; + +/** + * Terminal context properties provider factory. + */ +public final class TerminalContextPropertiesProviderFactory { + // Flag to remember if the contributions got loaded + private static boolean contributionsLoaded = false; + + // The list of all loaded contributions + private static final List contributions = new ArrayList(); + + // The proxy used to achieve lazy class loading and plug-in activation + private static class Proxy implements IExecutableExtension { + // Reference to the configuration element + private IConfigurationElement configElement = null; + // The class implementing the provider + public String clazz; + // The context properties provider instance + private ITerminalContextPropertiesProvider provider = null; + // The converted expression + private Expression expression; + + /** + * Constructor. + */ + protected Proxy() { + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + Assert.isNotNull(config); + this.configElement = config; + + // Read the class attribute. + // Throws an exception if the attribute value is empty or null. + clazz = config.getAttribute("class"); //$NON-NLS-1$ + if (clazz == null || "".equals(clazz.trim())) { //$NON-NLS-1$ + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.Extension_error_missingRequiredAttribute, "class", config.getContributor().getName()))); //$NON-NLS-1$ + } + + // Read the "enablement" sub element of the extension + IConfigurationElement[] children = configElement.getChildren("enablement"); //$NON-NLS-1$ + if (children == null || children.length == 0) { + throw new CoreException(new Status(IStatus.ERROR, + CoreBundleActivator.getUniqueIdentifier(), + NLS.bind(Messages.Extension_error_missingRequiredAttribute, "enablement", config.getContributor().getName()))); //$NON-NLS-1$ + } + // Only one "enablement" element is expected + expression = ExpressionConverter.getDefault().perform(children[0]); + } + + /** + * Return the real terminal context properties provider instance for this proxy. + */ + protected ITerminalContextPropertiesProvider getProvider() { + if (provider == null && configElement != null) { + try { + // Create the service class instance via the configuration element + Object provider = configElement.createExecutableExtension("class"); //$NON-NLS-1$ + if (provider instanceof ITerminalContextPropertiesProvider) { + this.provider = (ITerminalContextPropertiesProvider)provider; + } + else { + IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), "Terminal context properties provider '" + provider.getClass().getName() + "' not of type ITerminalContextPropertiesProvider."); //$NON-NLS-1$ //$NON-NLS-2$ + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), "Cannot create terminal context properties provider '" + clazz + "'.", e); //$NON-NLS-1$ //$NON-NLS-2$ + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + return provider; + } + + /** + * Returns if or if not the context properties provider contribution is enabled for + * the given terminal context. + * + * @param context The terminal context or null. + * @return True if the context properties provider contribution is enabled + * for the given terminal context, false otherwise. + */ + protected boolean isEnabled(Object context) { + if (context == null) { + return getEnablement() == null; + } + + Expression enablement = getEnablement(); + + // The service contribution is enabled by default if no expression is specified. + boolean enabled = enablement == null; + + if (enablement != null) { + // Set the default variable to the service context. + EvaluationContext evalContext = new EvaluationContext(null, context); + // Allow plug-in activation + evalContext.setAllowPluginActivation(true); + // Evaluate the expression + try { + enabled = enablement.evaluate(evalContext).equals(EvaluationResult.TRUE); + } catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e); + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(status); + } + } + + return enabled; + } + + /** + * Returns the enablement expression. + * + * @return The enablement expression or null. + */ + protected Expression getEnablement() { + return expression; + } + } + + + /** + * Creates a new terminal context properties provider proxy instance and initialize it. + * + * @param config The configuration element. Must not be null. + * @return The new terminal context properties provider proxy instance. + */ + private static Proxy getProxy(IConfigurationElement config) { + Assert.isNotNull(config); + Proxy proxy = new Proxy(); + try { + proxy.setInitializationData(config, null, null); + } catch (CoreException e) { + if (Platform.inDebugMode()) { + Platform.getLog(CoreBundleActivator.getContext().getBundle()).log(e.getStatus()); + } + } + return proxy; + } + + /** + * Load the terminal context properties provider contributions. + */ + private static void loadContributions() { + IExtensionPoint ep = Platform.getExtensionRegistry().getExtensionPoint("org.eclipse.tm.terminal.view.core.contextPropertiesProviders"); //$NON-NLS-1$ + if (ep != null) { + IExtension[] extensions = ep.getExtensions(); + if (extensions != null) { + for (IExtension extension : extensions) { + IConfigurationElement[] configElements = extension.getConfigurationElements(); + if (configElements != null) { + for (IConfigurationElement configElement : configElements) { + if ("contextPropertiesProvider".equals(configElement.getName())) { //$NON-NLS-1$ + Proxy proxy = getProxy(configElement); + contributions.add(proxy); + } + } + } + } + } + } + } + + /** + * Get the terminal context properties provider for the given context. The first terminal + * context properties provider which is enabled is returned. + * + * @param context The terminal context. Must not be null. + * + * @return The service or null. + */ + public static ITerminalContextPropertiesProvider getProvider(Object context) { + Assert.isNotNull(context); + + // Load the contributions if not yet loaded + synchronized (contributions) { + if (!contributionsLoaded) { + loadContributions(); + contributionsLoaded = true; + } + } + + for (Proxy proxy : contributions) { + if (proxy.isEnabled(context)) { + return proxy.getProvider(); + } + } + + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/TerminalServiceFactory.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/TerminalServiceFactory.java new file mode 100644 index 00000000000..bc26f8dc830 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/TerminalServiceFactory.java @@ -0,0 +1,53 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core; + +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.tm.terminal.view.core.activator.CoreBundleActivator; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.nls.Messages; +import org.osgi.framework.Bundle; + +/** + * Terminal service factory implementation. + *

            + * Provides access to the terminal service instance. + */ +public final class TerminalServiceFactory { + private static ITerminalService instance = null; + + static { + // Tries to instantiate the terminal service implementation + // from the o.e.tm.terminal.view.ui bundle + Bundle bundle = Platform.getBundle("org.eclipse.tm.terminal.view.ui"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + try { + Class clazz = bundle.loadClass("org.eclipse.tm.terminal.view.ui.services.TerminalService"); //$NON-NLS-1$ + instance = (ITerminalService) clazz.newInstance(); + } + catch (Exception e) { + if (Platform.inDebugMode()) { + Platform.getLog(bundle).log(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), Messages.TerminalServiceFactory_error_serviceImplLoadFailed, e)); + } + } + } + } + + /** + * Returns the terminal service instance. + */ + public static ITerminalService getService() { + return instance; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/activator/CoreBundleActivator.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/activator/CoreBundleActivator.java new file mode 100644 index 00000000000..4c309299909 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/activator/CoreBundleActivator.java @@ -0,0 +1,58 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.activator; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class CoreBundleActivator implements BundleActivator { + // The bundle context + private static BundleContext context; + + /** + * Returns the bundle context + * + * @return the bundle context + */ + public static BundleContext getContext() { + return context; + } + + /** + * Convenience method which returns the unique identifier of this plug-in. + */ + public static String getUniqueIdentifier() { + if (getContext() != null && getContext().getBundle() != null) { + return getContext().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.view.core"; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext bundleContext) throws Exception { + CoreBundleActivator.context = bundleContext; + } + + /* (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext bundleContext) throws Exception { + CoreBundleActivator.context = null; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalContextPropertiesProvider.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalContextPropertiesProvider.java new file mode 100644 index 00000000000..eefca07d8fd --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalContextPropertiesProvider.java @@ -0,0 +1,55 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces; + +import java.util.Map; + +/** + * Terminal context properties provider. + *

            + * The context properties provider allows querying desired properties + * for a given context. The context is typically an element from a selection + * and the inner structure of the element is unknown to the terminal. + */ +public interface ITerminalContextPropertiesProvider { + + /** + * Returns a unmodifiable map containing the target address and port for the given context, + * if it can be determined. + *

            + * A context may return multiple target addresses and ports if the context can be reached using + * different connection methods. + *

            + * Note: + *

              + *
            • See the constants defined in the context provider constants interface for default + * address and port types.
            • + *
            • The target address returned must not necessarily be an IP address.
            • + *
            • The values of the address or port properties might be null.
            • + *
            + * + * @param context The context to get the target addresses and ports from. Must not be null. + * @return The unmodifiable map containing the target addresses and ports, or null. + */ + public Map getTargetAddress(Object context); + + /** + * Returns the property value stored under the given property key. If the property does not + * exist, null is returned. + * + * @param context The context to get the property from. Must not be null. + * @param key The property key. Must not be null. + * + * @return The stored property value or null. + */ + public Object getProperty(Object context, String key); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalService.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalService.java new file mode 100644 index 00000000000..e28f1b42298 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalService.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces; + +import java.util.Map; + +import org.eclipse.core.runtime.IStatus; + +/** + * Terminal service. + */ +public interface ITerminalService { + + /** + * Client call back interface. + */ + public interface Done { + /** + * Called when the terminal service operation is done. + * + * @param status The status of the terminal service operation. + */ + public void done(IStatus status); + } + + /** + * Opens a terminal asynchronously and invokes the given callback if done. + * + * @param properties The terminal properties. Must not be null. + * @param done The callback to invoke if finished or null. + */ + public void openConsole(Map properties, Done done); + + /** + * Close the terminal asynchronously and invokes the given callback if done. + * + * @param properties The terminal properties. Must not be null. + * @param done The callback to invoke if finished or null. + */ + public void closeConsole(Map properties, Done done); + + /** + * Terminate (disconnect) the terminal asynchronously and invokes the given callback if done. + * + * @param properties The terminal properties. Must not be null. + * @param done The callback to invoke if finished or null. + */ + public void terminateConsole(Map properties, Done done); + + /** + * Register the given listener to receive notifications about terminal events. + * Calling this method multiple times with the same listener has no effect. + + * @param listener The terminal tab listener. Must not be null. + */ + public void addTerminalTabListener(ITerminalTabListener listener); + + /** + * Unregister the given listener from receiving notifications about terminal + * events. Calling this method multiple times with the same listener + * has no effect. + * + * @param listener The terminal tab listener. Must not be null. + */ + public void removeTerminalTabListener(ITerminalTabListener listener); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalServiceOutputStreamMonitorListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalServiceOutputStreamMonitorListener.java new file mode 100644 index 00000000000..b48a1113adf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalServiceOutputStreamMonitorListener.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2014 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces; + +/** + * An interface to be implemented by listeners who want to listen + * to the streams data without interfering with the original data receiver. + *

            + * Listeners are invoked within the monitor processing thread. + */ +public interface ITerminalServiceOutputStreamMonitorListener { + + /** + * Signals that some content has been read from the monitored stream. + * + * @param byteBuffer The byte stream. Must not be null. + * @param bytesRead The number of bytes that were read into the read buffer. + */ + public void onContentReadFromStream(byte[] byteBuffer, int bytesRead); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalTabListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalTabListener.java new file mode 100644 index 00000000000..bd3a034680b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/ITerminalTabListener.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces; + +/** + * Listener to implement and to register to get notified about + * terminal tabs events, like the disposal of a terminal tab. + */ +public interface ITerminalTabListener { + + /** + * Invoked once a terminal tab got disposed. The source object is + * the disposed tab item and data is the custom data object associated + * with the disposed tab item. + * + * @param source The disposed tab item. Must not be null. + * @param data The custom data object associated with the disposed tab item or null. + */ + public void terminalTabDisposed(Object source, Object data); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/IContextPropertiesConstants.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/IContextPropertiesConstants.java new file mode 100644 index 00000000000..55daaeecbc7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/IContextPropertiesConstants.java @@ -0,0 +1,52 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces.constants; + +/** + * Defines the terminal context properties constants. + */ +public interface IContextPropertiesConstants { + + /** + * Target name. + *

            + * The target name is not meant to be identical with the targets network name. It can + * be the targets network name, but it can be any other string identifying the target + * to the user as well. The name is for display only, it is not meant to be used for + * communicating with the target. + */ + public static String PROP_NAME = "name"; //$NON-NLS-1$ + + /** + * Target agent address. + *

            + * The value is typically the address an agent running at the target. + */ + public static String PROP_ADDRESS = "address"; //$NON-NLS-1$ + + /** + * Target agent port. + *

            + * The value is typically the port an agent running at the target. + */ + public static String PROP_PORT = "port"; //$NON-NLS-1$ + + /** + * The default user name to use to log into the target. + */ + public static String PROP_DEFAULT_USER = "defaultUser"; //$NON-NLS-1$ + + /** + * The default encoding to use. + */ + public static String PROP_DEFAULT_ENCODING = "defaultEncoding"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/ILineSeparatorConstants.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/ILineSeparatorConstants.java new file mode 100644 index 00000000000..f6888a22629 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/ILineSeparatorConstants.java @@ -0,0 +1,34 @@ +/******************************************************************************* + * Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces.constants; + +/** + * Line separator constants. + */ +public interface ILineSeparatorConstants { + + /** + * The line separator setting CR (carriage return only; for example, used by Mac OS 9). + */ + public final static String LINE_SEPARATOR_CR = "\\r"; //$NON-NLS-1$ + + /** + * The line separator setting CRLF (carriage return and line feed; for example, used by + * Windows). + */ + public final static String LINE_SEPARATOR_CRLF = "\\r\\n"; //$NON-NLS-1$ + + /** + * The line separator setting LF (line feed only; used by all UNIX-based systems). + */ + public final static String LINE_SEPARATOR_LF = "\\n"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/ITerminalsConnectorConstants.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/ITerminalsConnectorConstants.java new file mode 100644 index 00000000000..9c804202a35 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/interfaces/constants/ITerminalsConnectorConstants.java @@ -0,0 +1,338 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361352] [TERMINALS][SSH] Add SSH terminal support + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.interfaces.constants; + +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; + + +/** + * Defines the terminals connector constants. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITerminalsConnectorConstants { + + /** + * Property: The unique id of the terminals view to open. + *

            + * Property Type: {@link String} + */ + public static final String PROP_ID = "id"; //$NON-NLS-1$ + + /** + * Property: The unique secondary id of the terminals view to open. + *

            + * Property Type: {@link String} + */ + public static final String PROP_SECONDARY_ID = "secondaryId"; //$NON-NLS-1$ + + /** + * Property: The title of the terminal tab to open. + *

            + * Property Type: {@link String} + */ + public static final String PROP_TITLE = "title"; //$NON-NLS-1$ + + /** + * Property: The encoding of the terminal tab to open. + *

            + * Property Type: {@link String} + */ + public static final String PROP_ENCODING = "encoding"; //$NON-NLS-1$ + + /** + * Property: Custom data object to associate with the terminal tab. + *

            + * Property Type: {@link Object} + */ + public static final String PROP_DATA = "data"; //$NON-NLS-1$ + + /** + * Property: External selection to associate with the terminal tab. + *

            + * Property Type: {@link org.eclipse.jface.viewers.ISelection} + */ + public static final String PROP_SELECTION = "selection"; //$NON-NLS-1$ + + /** + * Property: Flag to force a new terminal tab. + *

            + * Property Type: {@link Boolean} + */ + public static final String PROP_FORCE_NEW = "terminal.forceNew"; //$NON-NLS-1$ + + /** + * Property: Terminal launcher delegate id. + *

            + * Property Type: {@link String} + */ + public static final String PROP_DELEGATE_ID = "delegateId"; //$NON-NLS-1$ + + /** + * Property: Specific terminal connector type id. Allows clients to + * override the specifically used terminal connector + * implementation for a given type. + *

            + * Property Type: {@link String} + */ + public static final String PROP_TERMINAL_CONNECTOR_ID = "tm.terminal.connector.id"; //$NON-NLS-1$ + + // ***** Generic terminals connector properties ***** + + /** + * Property: Timeout to be passed to the terminal connector. The specific terminal + * connector implementation may interpret this value differently. If not + * set, the terminal connector may use a default value. + *

            + * Property Type: {@link Integer} + */ + public static final String PROP_TIMEOUT = "timeout"; //$NON-NLS-1$ + + /** + * Property: Flag to control if a local echo is needed from the terminal widget. + *

            Typical for process and streams terminals. + *

            + * Property Type: {@link Boolean} + */ + public static final String PROP_LOCAL_ECHO = "localEcho"; //$NON-NLS-1$ + + /** + * Property: Data flag to tell the terminal to not reconnect when hitting enter + * in a disconnected terminal. + *

            + * Property Type: {@link Boolean} + */ + public static final String PROP_DATA_NO_RECONNECT = "data.noReconnect"; //$NON-NLS-1$ + + /** + * Property: The line separator expected by the remote terminal on input streams and + * send by the remote terminal on output streams. + *

            Typical for process and streams terminals. + *

            + * Property Type: {@link String} + */ + public static final String PROP_LINE_SEPARATOR = "lineSeparator"; //$NON-NLS-1$ + + /** + * Property: The list of stdout listeners to attach to the corresponding stream monitor. + *

            Typical for process and streams terminals. + *

            + * Property Type: {@link ITerminalServiceOutputStreamMonitorListener} array + */ + public static final String PROP_STDOUT_LISTENERS = "stdoutListeners"; //$NON-NLS-1$ + + /** + * Property: The list of stderr listeners to attach to the corresponding stream monitor. + *

            Typical for process and streams terminals. + *

            + * Property Type: {@link ITerminalServiceOutputStreamMonitorListener} array + */ + public static final String PROP_STDERR_LISTENERS = "stderrListeners"; //$NON-NLS-1$ + + /** + * Property: If set to true, backslashes are translated to + * slashes before pasting the text to the terminal widget. + *

            + * Property Type: {@link Boolean} + */ + public static final String PROP_TRANSLATE_BACKSLASHES_ON_PASTE = "translateBackslashesOnPaste"; //$NON-NLS-1$ + + // ***** IP based terminals connector properties ***** + + /** + * Property: Host name or IP address the terminal server is running. + *

            Typical for telnet or ssh terminals. + *

            + * Property Type: {@link String} + */ + public static final String PROP_IP_HOST = "ip.host"; //$NON-NLS-1$ + + /** + * Property: Port at which the terminal server is providing the console input and output. + *

            Typical for telnet or ssh terminals. + *

            + * Property Type: {@link Integer} + */ + public static final String PROP_IP_PORT = "ip.port"; //$NON-NLS-1$ + + /** + * Property: An offset to add to the specified port number. + *

            Typical for telnet or ssh terminals. + *

            + * Property Type: {@link Integer} + */ + public static final String PROP_IP_PORT_OFFSET = "ip.port.offset"; //$NON-NLS-1$ + + // ***** Process based terminals connector properties ***** + + /** + * Property: Process image path. + *

            Typical for process terminals. + *

            + * Property Type: {@link String} + */ + public static final String PROP_PROCESS_PATH = "process.path"; //$NON-NLS-1$ + + /** + * Property: Process arguments. + *

            Typical for process terminals. + *

            + * Property Type: {@link String} + */ + public static final String PROP_PROCESS_ARGS = "process.args"; //$NON-NLS-1$ + + /** + * Property: Process arguments. + *

            Typical for process terminals. + *

            + * Property Type: {@link String} + */ + public static final String PROP_PROCESS_WORKING_DIR = "process.working_dir"; //$NON-NLS-1$ + + /** + * Property: Process environment. + *

            Typical for process terminals. + *

            + * Property Type: {@link String} array + */ + public static final String PROP_PROCESS_ENVIRONMENT = "process.environment"; //$NON-NLS-1$ + + /** + * Property: Flag to merge process environment with native environment. + *

            Typical for process terminals. + *

            + * Property Type: {@link Boolean} + */ + public static final String PROP_PROCESS_MERGE_ENVIRONMENT = "process.environment.merge"; //$NON-NLS-1$ + + /** + * Property: Runtime process instance. + *

            Typical for process terminals. + *

            + * Property Type: {@link Process} + */ + public static final String PROP_PROCESS_OBJ = "process"; //$NON-NLS-1$ + + /** + * Property: Runtime process PTY instance. + *

            Typical for process terminals. + *

            + * Property Type: {@link org.eclipse.cdt.utils.pty.PTY} + */ + public static final String PROP_PTY_OBJ = "pty"; //$NON-NLS-1$ + + // ***** Streams based terminals connector properties ***** + + /** + * Property: Stdin streams instance. + *

            Typical for streams terminals. + *

            + * Property Type: {@link OutputStream} + */ + public static final String PROP_STREAMS_STDIN = "streams.stdin"; //$NON-NLS-1$ + + /** + * Property: Stdout streams instance. + *

            Typical for streams terminals. + *

            + * Property Type: {@link InputStream} + */ + public static final String PROP_STREAMS_STDOUT = "streams.stdout"; //$NON-NLS-1$ + + /** + * Property: Stderr streams instance. + *

            Typical for streams terminals. + *

            + * Property Type: {@link InputStream} + */ + public static final String PROP_STREAMS_STDERR = "streams.stderr"; //$NON-NLS-1$ + + // ***** Ssh specific properties ***** + + /** + * Property: ssh keep alive value. + *

            + * Property Type: {@link Integer} + */ + public static final String PROP_SSH_KEEP_ALIVE = "ssh.keep_alive"; //$NON-NLS-1$ + + /** + * Property: Ssh password. + *

            + * Property Type: {@link String} + */ + public static final String PROP_SSH_PASSWORD = "ssh.password"; //$NON-NLS-1$ + + /** + * Property: Ssh user. + *

            + * Property Type: {@link String} + */ + public static final String PROP_SSH_USER = "ssh.user"; //$NON-NLS-1$ + + // ***** Serial specific properties ***** + + /** + * The serial device name. + *

            + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_DEVICE = "serial.device"; //$NON-NLS-1$ + + /** + * The baud rate. + *

            + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_BAUD_RATE = "serial.baudrate"; //$NON-NLS-1$ + + /** + * The data bits + *

            + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_DATA_BITS = "serial.databits"; //$NON-NLS-1$ + + /** + * The parity + *

            + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_PARITY = "serial.parity"; //$NON-NLS-1$ + + /** + * The stop bits + *

            + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_STOP_BITS = "serial.stopbits"; //$NON-NLS-1$ + + /** + * The flow control + *

            + * Property Type: {@link String} + */ + public static final String PROP_SERIAL_FLOW_CONTROL = "serial.flowcontrol"; //$NON-NLS-1$ + + // ***** Telnet specific properties ***** + + /** + * The end-of-line sequence to be sent to the server on "Enter". + *

            + * Property Type: {@link String} + * @since 4.2 + */ + public static final String PROP_TELNET_EOL = "telnet.eol"; //$NON-NLS-1$ + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/internal/PropertyTester.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/internal/PropertyTester.java new file mode 100644 index 00000000000..402cd67a5ce --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/internal/PropertyTester.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.internal; + +import org.eclipse.tm.terminal.view.core.TerminalContextPropertiesProviderFactory; + + + +/** + * Property tester implementation. + */ +public class PropertyTester extends org.eclipse.core.expressions.PropertyTester { + + /* (non-Javadoc) + * @see org.eclipse.core.expressions.IPropertyTester#test(java.lang.Object, java.lang.String, java.lang.Object[], java.lang.Object) + */ + @Override + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + + // "hasContextPropertiesProvider": Checks if a context properties provider is available for the given receiver. + if ("hasContextPropertiesProvider".equals(property)) { //$NON-NLS-1$ + boolean hasProvider = TerminalContextPropertiesProviderFactory.getProvider(receiver) != null; + return expectedValue instanceof Boolean ? ((Boolean)expectedValue).equals(Boolean.valueOf(hasProvider)) : hasProvider; + } + + return false; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/nls/Messages.java new file mode 100644 index 00000000000..2d778f3b126 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/nls/Messages.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.nls; + +import org.eclipse.osgi.util.NLS; + +/** + * Externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.view.core.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + // **** Declare externalized string id's down here ***** + + public static String TerminalServiceFactory_error_serviceImplLoadFailed; + + public static String Extension_error_missingRequiredAttribute; +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/nls/Messages.properties new file mode 100644 index 00000000000..647a26ff699 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/nls/Messages.properties @@ -0,0 +1,16 @@ +############################################################################### +# Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +TerminalServiceFactory_error_serviceImplLoadFailed=Failed to load terminal service implementation. + +Extension_error_missingRequiredAttribute=Required attribute "{0}" missing for extension "{1}"! + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/preferences/ScopedEclipsePreferences.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/preferences/ScopedEclipsePreferences.java new file mode 100644 index 00000000000..44654520423 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/preferences/ScopedEclipsePreferences.java @@ -0,0 +1,461 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.preferences; + +import java.io.OutputStream; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IEclipsePreferences; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.IPreferenceChangeListener; +import org.eclipse.core.runtime.preferences.IEclipsePreferences.PreferenceChangeEvent; +import org.eclipse.core.runtime.preferences.IPreferenceFilter; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.osgi.service.prefs.BackingStoreException; + +/** + * Helper class to handle scoped Eclipse preferences for plug-in's. Scoped + * preferences means a given preference context plus the default preferences + * scope. + *

            + * On changes a {@link PreferenceChangeEvent} is sent to inform all listeners of the change. + * + * @see IEclipsePreferences + * @see IEclipsePreferences.PreferenceChangeEvent + * @see IEclipsePreferences.IPreferenceChangeListener + */ +public class ScopedEclipsePreferences { + /** + * The preferences scope qualifier. + */ + private final String qualifier; + + /** + * The default scope preference node. + */ + protected final IEclipsePreferences defaultPrefs; + + /** + * The context scope preference node. + */ + protected final IEclipsePreferences contextScopePrefs; + + /** + * The registered preference change listeners. + */ + private final ListenerList listeners = new ListenerList(); + + /** + * Constructor. + *

            + * Initialize the scoped preferences with a new instance scope for the given qualifier. The default + * scope is determined by calling DefaultScope().getNode(qualifier). + * + * @param qualifier The qualifier for the preferences (in example the unique identifier of a plugin). Must not be null. + */ + public ScopedEclipsePreferences(String qualifier) { + this(InstanceScope.INSTANCE, qualifier); + } + + /** + * Constructor. + *

            + * Initialize the scoped preferences with the given scope. The default scope + * is determined by calling DefaultScope().getNode(qualifier). + * + * @param context The preference scope context. Must not be null. + * @param qualifier The qualifier for the preferences (in example the unique identifier of a plugin). Must not be null. + */ + public ScopedEclipsePreferences(IScopeContext context, String qualifier) { + Assert.isNotNull(context); + Assert.isNotNull(qualifier); + this.qualifier = qualifier; + defaultPrefs = DefaultScope.INSTANCE.getNode(getQualifier()); + contextScopePrefs = context.getNode(getQualifier()); + } + + /** + * Returns the qualifier that is used to get the preferences. + * For plugin preferences, this is the unique identifier of the plugin. + */ + protected final String getQualifier() { + return qualifier; + } + + /** + * Exports the preferences to the stream. + *

            + * Note: The stream will be closed after the export. + * + * @param stream The stream to where preferences and defaults should be exported. + */ + public void exportPreferences(OutputStream stream) { + Assert.isNotNull(stream); + try { + IPreferenceFilter filter = new IPreferenceFilter() { + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IPreferenceFilter#getScopes() + */ + @Override + public String[] getScopes() { + return new String[] { InstanceScope.SCOPE }; + } + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.IPreferenceFilter#getMapping(java.lang.String) + */ + @Override + public Map getMapping(String scope) { + return null; + } + }; + + Platform.getPreferencesService().exportPreferences(contextScopePrefs, new IPreferenceFilter[] { filter }, stream); + stream.close(); + } + catch (Exception e) { + } + } + + /** + * Check whether a key is set or not. + * + * @param key The key to check. + * @return null if the key does not exist. + */ + public boolean containsKey(String key) { + return Platform.getPreferencesService().getString(getQualifier(), key, null, null) != null; + } + + /** + * Get a String preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final String getString(String key) { + return Platform.getPreferencesService().getString(getQualifier(), key, null, null); + } + + /** + * Get a boolean preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final boolean getBoolean(String key) { + return Platform.getPreferencesService().getBoolean(getQualifier(), key, false, null); + } + + /** + * Get an int preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final int getInt(String key) { + return Platform.getPreferencesService().getInt(getQualifier(), key, 0, null); + } + + /** + * Get a long preference value. + * + * @param key The preference key. + * @return The value of the preference key or the default value if not set. + */ + public final long getLong(String key) { + return Platform.getPreferencesService().getLong(getQualifier(), key, 0, null); + } + + /** + * Get a default String preference value. + * + * @param key The preference key. + * @return The default value of the preference key or null. + */ + public final String getDefaultString(String key) { + return defaultPrefs.get(key, null); + } + + /** + * Get a default boolean preference value. + * + * @param key The preference key. + * @return The default value of the preference key or null. + */ + public final boolean getDefaultBoolean(String key) { + return defaultPrefs.getBoolean(key, false); + } + + /** + * Get a default int preference value. + * + * @param key The preference key. + * @return The default value of the preference key or null. + */ + public final int getDefaultInt(String key) { + return defaultPrefs.getInt(key, 0); + } + + /** + * Get a default long preference value. + * + * @param key The preference key. + * @return The default value of the preference key or null. + */ + public final long getDefaultLong(String key) { + return defaultPrefs.getLong(key, 0); + } + + /** + * Set a String preference value. If the value is null or is equal to + * the default value, the entry will be removed. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putString(String key, String value) { + String defValue = defaultPrefs.get(key, null); + String instValue = getString(key); + if (value == null || value.equals(defValue)) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, instValue, defValue); + } + else if (!value.equals(instValue)) { + contextScopePrefs.put(key, value); + flushAndNotify(contextScopePrefs, key, instValue, value); + } + } + + /** + * Set a boolean preference value. If the value is equal the default value, + * the entry will be removed. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putBoolean(String key, boolean value) { + boolean defValue = defaultPrefs.getBoolean(key, false); + boolean instValue = getBoolean(key); + if (value == defValue) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, Boolean.toString(instValue), Boolean.toString(defValue)); + } + else if (value != instValue) { + contextScopePrefs.putBoolean(key, value); + flushAndNotify(contextScopePrefs, key, Boolean.toString(instValue), Boolean.toString(value)); + } + } + + /** + * Set an int preference value. If the value is equal to the default value, + * the entry will be removed. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putInt(String key, int value) { + int defValue = defaultPrefs.getInt(key, 0); + int instValue = getInt(key); + if (value == defValue) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, Integer.toString(instValue), Integer.toString(defValue)); + } + else if (value != instValue) { + contextScopePrefs.putInt(key, value); + flushAndNotify(contextScopePrefs, key, Integer.toString(instValue), Integer.toString(value)); + } + } + + /** + * Set a long preference value. If the given value is equal to the default + * value, the entry will be removed. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The value of the preference key. + */ + public void putLong(String key, long value) { + long defValue = defaultPrefs.getLong(key, 0); + long instValue = getLong(key); + if (value == defValue) { + contextScopePrefs.remove(key); + flushAndNotify(contextScopePrefs, key, Long.toString(instValue), Long.toString(defValue)); + } + else if (value != instValue) { + contextScopePrefs.putLong(key, value); + flushAndNotify(contextScopePrefs, key, Long.toString(instValue), Long.toString(value)); + } + } + + /** + * Set a default String preference value. If the given value is null, + * the entry will be removed. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultString(String key, String value) { + String defValue = defaultPrefs.get(key, null); + if (value == null) { + defaultPrefs.remove(key); + flushAndNotify(defaultPrefs, key, defValue, null); + } + else if (!value.equals(defValue)) { + defaultPrefs.put(key, value); + flushAndNotify(defaultPrefs, key, defValue, value); + } + } + + /** + * Set a default boolean preference value. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultBoolean(String key, boolean value) { + boolean defValue = defaultPrefs.getBoolean(key, false); + if (value != defValue) { + defaultPrefs.putBoolean(key, value); + flushAndNotify(defaultPrefs, key, Boolean.toString(defValue), Boolean.toString(value)); + } + } + + /** + * Set a default int preference value. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultInt(String key, int value) { + int defValue = defaultPrefs.getInt(key, 0); + if (value != defValue) { + defaultPrefs.putInt(key, value); + flushAndNotify(defaultPrefs, key, Integer.toString(defValue), Integer.toString(value)); + } + } + + /** + * Set a default long preference value. + *

            + * A {@link PreferenceChangeEvent} is fired, if the value has changed. The old + * and new values are string representation in base 10. + * + * @param key The preference key. + * @return The default value of the preference key. + */ + public void putDefaultLong(String key, long value) { + long defValue = defaultPrefs.getLong(key, 0); + if (value != defValue) { + defaultPrefs.putLong(key, value); + flushAndNotify(defaultPrefs, key, Long.toString(defValue), Long.toString(value)); + } + } + + /** + * Write back the changes to the store and notify all listeners about the changed key. + * + * @param node The preference node which has changed. Must not be null. + * @param key The key of the changed preference. Must not be null. + * @param oldValue The old value as a {@link String}, or null. + * @param newValue The new value as a {@link String}, or null. + */ + protected final void flushAndNotify(IEclipsePreferences node, String key, String oldValue, String newValue) { + // Flush the preferences to the persistence store + try { node.flush(); } catch (BackingStoreException e) { /* Ignored on purpose */ } + + // Notify the listeners + firePreferenceEvent(node, key, oldValue, newValue); + } + + /** + * Register the given listener to receive notifications of preference changes to this node. + * Calling this method multiple times with the same listener has no effect. The given listener + * argument must not be null. + * + * @param listener The preference change listener. Must not be null. + */ + public void addPreferenceChangeListener(IPreferenceChangeListener listener) { + Assert.isNotNull(listener); + listeners.add(listener); + } + + /** + * De-register the given listener from receiving notifications of preference changes + * to this node. Calling this method multiple times with the same listener has no + * effect. The given listener argument must not be null. + * + * @param listener The preference change listener. Must not be null. + */ + public void removePreferenceChangeListener(IPreferenceChangeListener listener) { + Assert.isNotNull(listener); + listeners.remove(listener); + } + + /** + * Convenience method for notifying the registered preference change listeners. + * + * @param node The preference node which has changed. Must not be null. + * @param key The key of the changed preference. Must not be null. + * @param oldValue The old value as a {@link String}, or null. + * @param newValue The new value as a {@link String}, or null. + */ + protected void firePreferenceEvent(IEclipsePreferences node, String key, String oldValue, String newValue) { + Assert.isNotNull(node); + Assert.isNotNull(key); + + // If no listener is registered, we are done here + if (listeners.isEmpty()) return; + + // Get the list or currently registered listeners + Object[] l = listeners.getListeners(); + // Create the preference change event + final PreferenceChangeEvent event = new PreferenceChangeEvent(node, key, oldValue, newValue); + for (int i = 0; i < l.length; i++) { + final IPreferenceChangeListener listener = (IPreferenceChangeListener) l[i]; + ISafeRunnable job = new ISafeRunnable() { + @Override + public void handleException(Throwable exception) { + // already logged in Platform#run() + } + + @Override + public void run() throws Exception { + listener.preferenceChange(event); + } + }; + SafeRunner.run(job); + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/tracing/TraceHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/tracing/TraceHandler.java new file mode 100644 index 00000000000..d14537533a5 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/tracing/TraceHandler.java @@ -0,0 +1,297 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.tracing; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.tm.terminal.view.core.activator.CoreBundleActivator; + +/** + * Helper class to handle tracing using the platforms debug capabilities. + */ +public class TraceHandler { + /** + * The bundle identifier. + */ + private final String identifier; + + /** + * The tracer instance. + */ + private Tracer tracer = null; + + /** + * The tracer is responsible for writing the trace message to the desired + * output media. + */ + protected static class Tracer { + + /** + * The bundle identifier. + */ + private final String fIdentifier; + + /** + * The qualifier for the default "<bundle identifier>/debugmode" + * tracing slot. + */ + private final String fDebugModeQualifier; + + /** + * Constructor. + * + * @param identifier The bundle identifier. Must not be null. + */ + public Tracer(String identifier) { + Assert.isNotNull(identifier); + fIdentifier = identifier; + + // Initialize the debug mode qualifier + fDebugModeQualifier = fIdentifier + "/debugmode"; //$NON-NLS-1$ + } + + /** + * Returns the value of the debug mode tracing slot. + *

            + * If not set, or the value is not an {@link Integer}, the method returns 0. + * + * @return The debug mode value. + */ + protected int getDebugMode() { + try { + String mode = Platform.getDebugOption(fDebugModeQualifier); + if (mode != null && Integer.decode(mode).intValue() > 0) { + return Integer.decode(mode).intValue(); + } + } catch (NumberFormatException e) { /* ignored on purpose */ } + + return 0; + } + + /** + * Check if the specified trace slot is enabled. + * + * @param slotId The name of the slot. + * @return true if the slot is defined and enabled, false otherwise. + */ + protected boolean isSlotEnabled(String slotId) { + return fIdentifier != null ? Boolean.parseBoolean(Platform.getDebugOption(fIdentifier + "/" + slotId)) : false; //$NON-NLS-1$ + } + + /** + * Check if tracing is enabled for given mode and slot. + * + * @param debugMode The debug mode for the current debug. + * @param slotId The name of the slot. + * + * @return true if the debug should be written, false otherwise. + */ + protected final boolean isEnabled(int debugMode, String slotId) { + return getDebugMode() < 0 || + (debugMode <= getDebugMode() && + (slotId == null || slotId.trim().length() == 0 || isSlotEnabled(slotId))); + } + + /** + * Format the trace message. + * + * @param message The trace message. + * @param debugMode The debug mode. + * @param slotId The name of the slot. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer. + * + * @see IStatus + */ + protected String getFormattedDebugMessage(String message, int debugMode, String slotId, int severity, Object clazz) { + StringBuffer debug = new StringBuffer(); + if (slotId != null || clazz != null) { + if (clazz != null) { + String name = clazz instanceof Class ? ((Class)clazz).getSimpleName() : clazz.getClass().getSimpleName(); + debug.append(name.trim().length() > 0 ? name.trim() : clazz instanceof Class ? ((Class)clazz).getName() : clazz.getClass().getName()); + } + if (slotId != null) { + debug.append(" at "); //$NON-NLS-1$ + debug.append(slotId); + } + if (debugMode >= 0) { + debug.append(" (Mode "); //$NON-NLS-1$ + debug.append(debugMode); + debug.append(')'); + } + debug.append('\n'); + debug.append('\t'); + } + debug.append(message); + + return debug.toString(); + } + + /** + * Write the trace message. + * + * @param message The trace message. + * @param debugMode The debug mode. + * @param slotId The name of the slot. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer. + * + * @see IStatus + */ + protected void write(String message, int debugMode, String slotId, int severity, Object clazz) { + String formattedMessage = getFormattedDebugMessage(message, debugMode, slotId, severity, clazz); + if (severity == IStatus.ERROR || severity == IStatus.WARNING) { + System.err.println(formattedMessage); + } + else { + System.out.println(formattedMessage); + } + } + + /** + * Trace the given message with the given debug mode and slot. + * + * @param message The trace message. + * @param debugMode The debug mode. + * @param slotId The name of the slot. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer. + * + * @see IStatus + */ + public final void trace(String message, int debugMode, String slotId, int severity, Object clazz) { + if (isEnabled(debugMode, slotId)) { + write(message, debugMode, slotId, severity, clazz); + } + } + } + + /** + * Constructor. + *

            + * Initializes the tracing handler with the given bundle identifier. + * + * @param identifier The bundle identifier or null. + */ + public TraceHandler(String identifier) { + this.identifier = identifier != null ? identifier : CoreBundleActivator.getUniqueIdentifier(); + Assert.isNotNull(this.identifier); + } + + /** + * Returns the identifier. + */ + protected final String getIdentifier() { + return identifier; + } + + /** + * Returns the tracer instance. Create a new tracer instance + * on first invocation. + * + * @return The tracer instance. + */ + protected Tracer getTracer() { + if (tracer == null) { + tracer = new Tracer(identifier); + } + return tracer; + } + + /** + * Return the current debug mode. + */ + public final int getDebugMode() { + return getTracer().getDebugMode(); + } + + /** + * Check whether a trace slot is enabled. The debug mode defaults + * to 0. + * + * @param slotId The name of the slot. + * + * @return true if the slot is enabled, false otherwise. + */ + public final boolean isSlotEnabled(String slotId) { + return isSlotEnabled(0, slotId); + } + + /** + * Check whether a trace slot is enabled with the given debug mode. + * + * @param debugMode The debug mode + * @param slotId The name of the slot. + * + * @return true if the slot is enabled, false otherwise. + */ + public final boolean isSlotEnabled(int debugMode, String slotId) { + return getTracer().isEnabled(debugMode, slotId); + } + + /** + * Trace the given message. + *

            + * The message severity will be {@link IStatus#INFO} and the message will be + * traced unconditionally. + * + * @param message The message. + * @param clazz The class that calls this tracer or null. + */ + public final void trace(String message, Object clazz) { + getTracer().trace(message, 0, null, IStatus.INFO, clazz); + } + + /** + * Trace the given message. + *

            + * The message severity will be {@link IStatus#INFO}. + * + * @param message The message. + * @param debugMode The minimum debug mode that has to be set to write out the message. + * @param clazz The class that calls this tracer or null. + */ + public final void trace(String message, int debugMode, Object clazz) { + getTracer().trace(message, debugMode, null, IStatus.INFO, clazz); + } + + /** + * Trace the given message. + *

            + * The message severity will be {@link IStatus#INFO} and the debug mode + * will default to 0. + * + * @param message The message. + * @param slotId The slot that has to be enabled to write out the message. + * @param clazz The class that calls this tracer or null. + */ + public final void trace(String message, String slotId, Object clazz) { + getTracer().trace(message, 0, slotId, IStatus.INFO, clazz); + } + + /** + * Trace the given message. + * + * @param message The message. + * @param debugMode The minimum debug mode that has to be set to write out the message. + * @param slotId The slot that has to be enabled to write out the message. + * @param severity The severity. See {@link IStatus} for valid severity values. + * @param clazz The class that calls this tracer or null. + * + * @see IStatus + */ + public final void trace(String message, int debugMode, String slotId, int severity, Object clazz) { + getTracer().trace(message, debugMode, slotId, severity, clazz); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/utils/Env.java b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/utils/Env.java new file mode 100644 index 00000000000..c44ed9b5e78 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.core/src/org/eclipse/tm/terminal/view/core/utils/Env.java @@ -0,0 +1,235 @@ +/******************************************************************************* + * Copyright (c) 2013, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.core.utils; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Platform; +import org.eclipse.osgi.service.environment.Constants; + +/** + * Environment handling utility methods. + */ +public class Env { + + // Reference to the monitor to lock if determining the native environment + private final static Object ENV_GET_MONITOR = new Object(); + + // Reference to the native environment with the case of the variable names preserved + private static Map nativeEnvironmentCasePreserved = null; + + /** + * Returns the merged environment of the native environment and the passed + * in environment. Passed in variables will overwrite the native environment + * if the same variables are set there. + *

            + * For use with terminals, the parameter terminal should be set to + * true. In this case, the method will assure that the TERM + * environment variable is always set to ANSI and is not overwritten + * by the passed in environment. + * + * @param envp The environment to set on top of the native environment or null. + * @param terminal True if used with an terminal, false otherwise. + * + * @return The merged environment. + */ + public static String[] getEnvironment(String[] envp, boolean terminal) { + // Get the cached native environment + Map nativeEnv = getNativeEnvironmentCasePreserved(); + // Make a copy of the native environment so it can be manipulated without changing + // the cached environment + Map env = new LinkedHashMap(nativeEnv); + // Set the TERM environment variable if in terminal mode + if (terminal) env.put("TERM", "xterm"); //$NON-NLS-1$ //$NON-NLS-2$ + + // On Windows, the environment variable names are not case-sensitive. However, + // we desire to preserve the original case. Build up a translation map between + // an all lowercase name and the original environment name + Map k2n = null; + if (Platform.OS_WIN32.equals(Platform.getOS())) { + k2n = new HashMap(); + for (String name : env.keySet()) { + k2n.put(name.toLowerCase(), name); + } + } + + // If a "local" environment is provided, merge it with the native + // environment. + if (envp != null) { + for (int i = 0; i < envp.length; i++) { + // The full provided variable in form "name=value" + String envpPart = envp[i]; + // Split the variable + int eqIdx = envpPart.indexOf('='); + if (eqIdx < 1) + continue; + String name = envpPart.substring(0, eqIdx); + // Map the variable name to the real environment name (Windows only) + if (Platform.OS_WIN32.equals(Platform.getOS())) { + if (k2n.containsKey(name.toLowerCase())) { + String candidate = k2n.get(name.toLowerCase()); + Assert.isNotNull(candidate); + name = candidate; + } + // Filter out environment variables with bad names + if ("".equals(name.trim()) || name.contains(":")) { //$NON-NLS-1$ //$NON-NLS-2$ + continue; + } + } + // Get the variable value + String value = envpPart.substring(eqIdx+1); + // Don't overwrite the TERM variable if in terminal mode + if (terminal && "TERM".equals(name)) continue; //$NON-NLS-1$ + // If a variable with the name does not exist, just append it + if (!env.containsKey(name) && !"".equals(value)) { //$NON-NLS-1$ + env.put(name, value); + } else if (env.containsKey(name)) { + // If the value contains the special placeholder "", remove the variable from the environment + if ("".equals(value)) {//$NON-NLS-1$ + env.remove(name); + } else { + // A variable with the name already exist, check if the value is different + String oldValue = env.get(name); + if (oldValue != null && !oldValue.equals(value) || oldValue == null && value != null) { + env.put(name, value); + } + } + } + } + } + + // Convert into an array of strings + List keys = new ArrayList(env.keySet()); + // On Windows hosts, sort the environment keys + if (Platform.OS_WIN32.equals(Platform.getOS())) Collections.sort(keys); + Iterator iter = keys.iterator(); + List strings = new ArrayList(env.size()); + StringBuilder buffer = null; + while (iter.hasNext()) { + String key = iter.next(); + buffer = new StringBuilder(key); + buffer.append('=').append(env.get(key)); + strings.add(buffer.toString()); + } + + return strings.toArray(new String[strings.size()]); + } + + /** + * Determine the native environment. + * + * @return The native environment, or an empty map. + */ + private static Map getNativeEnvironmentCasePreserved() { + synchronized (ENV_GET_MONITOR) { + if (nativeEnvironmentCasePreserved == null) { + nativeEnvironmentCasePreserved = new LinkedHashMap(); + cacheNativeEnvironment(nativeEnvironmentCasePreserved); + } + return new LinkedHashMap(nativeEnvironmentCasePreserved); + } + } + + /** + * Query the native environment and store it to the specified cache. + * + * @param cache The environment cache. Must not be null. + */ + private static void cacheNativeEnvironment(Map cache) { + Assert.isNotNull(cache); + + try { + String nativeCommand = null; + if (Platform.getOS().equals(Constants.OS_WIN32)) { + nativeCommand = "cmd.exe /C set"; //$NON-NLS-1$ + } else if (!Platform.getOS().equals(Constants.OS_UNKNOWN)) { + nativeCommand = "env"; //$NON-NLS-1$ + } + if (nativeCommand == null) { return; } + Process process = Runtime.getRuntime().exec(nativeCommand); + + // read process directly on other platforms + // we need to parse out matching '{' and '}' for function declarations in .bash environments + // pattern is [function name]=() { and we must find the '}' on its own line with no trailing ';' + InputStream stream = process.getInputStream(); + InputStreamReader isreader = new InputStreamReader(stream); + BufferedReader reader = new BufferedReader(isreader); + try { + String line = reader.readLine(); + while (line != null) { + String key = null; + String value = null; + int func = line.indexOf("=()"); //$NON-NLS-1$ + if (func > 0) { + key = line.substring(0, func); + // scan until we find the closing '}' with no following chars + value = line.substring(func + 1); + do { + line = reader.readLine(); + if (line == null) + break; + if (line.equals("}")) //$NON-NLS-1$ + value += ';'; + value += ' ' + line; + } while (!line.equals("}")); //$NON-NLS-1$ + line = reader.readLine(); + } else { + int separator = line.indexOf('='); + if (separator > 0) { + key = line.substring(0, separator); + value = line.substring(separator + 1); + StringBuilder bufValue = new StringBuilder(value); + line = reader.readLine(); + if (line != null) { + // this line has a '=' read ahead to check next line for '=', might be broken on more + // than one line + separator = line.indexOf('='); + while (separator < 0) { + bufValue.append(line.trim()); + line = reader.readLine(); + if (line == null) { + // if next line read is the end of the file quit the loop + break; + } + separator = line.indexOf('='); + } + } + value = bufValue.toString(); + } + } + if (key != null) { + cache.put(key, value); + } else { + line = reader.readLine(); + } + } + } finally { + reader.close(); + } + } catch (IOException e) { + // Native environment-fetching code failed. + // This can easily happen and is not useful to log. + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.core/tm32.png b/terminal/plugins/org.eclipse.tm.terminal.view.core/tm32.png new file mode 100644 index 00000000000..668b05b7913 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.core/tm32.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.classpath b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.classpath new file mode 100644 index 00000000000..ad32c83a788 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.gitignore b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.gitignore new file mode 100644 index 00000000000..ae3c1726048 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.gitignore @@ -0,0 +1 @@ +/bin/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.options b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.options new file mode 100644 index 00000000000..2b37de4fb78 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.options @@ -0,0 +1,3 @@ +org.eclipse.tm.terminal.view.ui/debugmode = 0 +org.eclipse.tm.terminal.view.ui/trace/outputStreamMonitor = false +org.eclipse.tm.terminal.view.ui/trace/launchTerminalCommandHandler = false diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.project b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.project new file mode 100644 index 00000000000..3686758258d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.project @@ -0,0 +1,45 @@ + + + org.eclipse.tm.terminal.view.ui + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + org.eclipse.pde.api.tools.apiAnalysisBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + org.eclipse.pde.api.tools.apiAnalysisNature + + + + 1329502074611 + + 10 + + org.eclipse.ui.ide.multiFilter + 1.0-name-matches-false-false-target + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.jdt.core.prefs b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 00000000000..5cb95e247ec --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,362 @@ +#Fri Oct 07 16:14:53 CEST 2011 +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 +org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve +org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.debug.lineNumber=generate +org.eclipse.jdt.core.compiler.debug.localVariable=generate +org.eclipse.jdt.core.compiler.debug.sourceFile=generate +org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.autoboxing=warning +org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning +org.eclipse.jdt.core.compiler.problem.deadCode=warning +org.eclipse.jdt.core.compiler.problem.deprecation=warning +org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=enabled +org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=enabled +org.eclipse.jdt.core.compiler.problem.discouragedReference=warning +org.eclipse.jdt.core.compiler.problem.emptyStatement=warning +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning +org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled +org.eclipse.jdt.core.compiler.problem.fieldHiding=warning +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.includeNullInfoFromAsserts=enabled +org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning +org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore +org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error +org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=ignore +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled +org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning +org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=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=warning +org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=error +org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore +org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning +org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore +org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning +org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning +org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=warning +org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning +org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore +org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore +org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled +org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning +org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled +org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled +org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=warning +org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning +org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled +org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning +org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore +org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryElse=warning +org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning +org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +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.unusedObjectAllocation=warning +org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore +org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=enabled +org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=enabled +org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning +org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning +org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning +org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.formatter.align_type_members_on_columns=false +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0 +org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_assignment=0 +org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_compact_if=0 +org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0 +org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0 +org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0 +org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80 +org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16 +org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0 +org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16 +org.eclipse.jdt.core.formatter.blank_lines_after_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_after_package=1 +org.eclipse.jdt.core.formatter.blank_lines_before_field=0 +org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0 +org.eclipse.jdt.core.formatter.blank_lines_before_imports=1 +org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1 +org.eclipse.jdt.core.formatter.blank_lines_before_method=1 +org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1 +org.eclipse.jdt.core.formatter.blank_lines_before_package=0 +org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1 +org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1 +org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line +org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=true +org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false +org.eclipse.jdt.core.formatter.comment.format_block_comments=true +org.eclipse.jdt.core.formatter.comment.format_header=false +org.eclipse.jdt.core.formatter.comment.format_html=true +org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true +org.eclipse.jdt.core.formatter.comment.format_line_comments=true +org.eclipse.jdt.core.formatter.comment.format_source_code=true +org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true +org.eclipse.jdt.core.formatter.comment.indent_root_tags=true +org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert +org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=do not insert +org.eclipse.jdt.core.formatter.comment.line_length=100 +org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true +org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true +org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false +org.eclipse.jdt.core.formatter.compact_else_if=true +org.eclipse.jdt.core.formatter.continuation_indentation=4 +org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=4 +org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off +org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on +org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false +org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true +org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true +org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_empty_lines=false +org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true +org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true +org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false +org.eclipse.jdt.core.formatter.indentation.size=4 +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert +org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=insert +org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert +org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert +org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert +org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert +org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert +org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert +org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert +org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert +org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert +org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert +org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert +org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert +org.eclipse.jdt.core.formatter.join_lines_in_comments=true +org.eclipse.jdt.core.formatter.join_wrapped_lines=true +org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=true +org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false +org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=true +org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=true +org.eclipse.jdt.core.formatter.lineSplit=100 +org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false +org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false +org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0 +org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1 +org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true +org.eclipse.jdt.core.formatter.tabulation.char=tab +org.eclipse.jdt.core.formatter.tabulation.size=4 +org.eclipse.jdt.core.formatter.use_on_off_tags=false +org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true +org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true +org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true +org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.jdt.ui.prefs b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.jdt.ui.prefs new file mode 100644 index 00000000000..0d732269684 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.jdt.ui.prefs @@ -0,0 +1,62 @@ +eclipse.preferences.version=1 +editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true +formatter_profile=_Target Explorer Java STD +formatter_settings_version=12 +sp_cleanup.add_default_serial_version_id=true +sp_cleanup.add_generated_serial_version_id=false +sp_cleanup.add_missing_annotations=true +sp_cleanup.add_missing_deprecated_annotations=true +sp_cleanup.add_missing_methods=false +sp_cleanup.add_missing_nls_tags=false +sp_cleanup.add_missing_override_annotations=true +sp_cleanup.add_missing_override_annotations_interface_methods=true +sp_cleanup.add_serial_version_id=false +sp_cleanup.always_use_blocks=true +sp_cleanup.always_use_parentheses_in_expressions=false +sp_cleanup.always_use_this_for_non_static_field_access=false +sp_cleanup.always_use_this_for_non_static_method_access=false +sp_cleanup.convert_functional_interfaces=false +sp_cleanup.convert_to_enhanced_for_loop=false +sp_cleanup.correct_indentation=false +sp_cleanup.format_source_code=false +sp_cleanup.format_source_code_changes_only=false +sp_cleanup.insert_inferred_type_arguments=false +sp_cleanup.make_local_variable_final=false +sp_cleanup.make_parameters_final=false +sp_cleanup.make_private_fields_final=true +sp_cleanup.make_type_abstract_if_missing_method=false +sp_cleanup.make_variable_declarations_final=false +sp_cleanup.never_use_blocks=false +sp_cleanup.never_use_parentheses_in_expressions=true +sp_cleanup.on_save_use_additional_actions=true +sp_cleanup.organize_imports=true +sp_cleanup.qualify_static_field_accesses_with_declaring_class=false +sp_cleanup.qualify_static_member_accesses_through_instances_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_through_subtypes_with_declaring_class=true +sp_cleanup.qualify_static_member_accesses_with_declaring_class=false +sp_cleanup.qualify_static_method_accesses_with_declaring_class=false +sp_cleanup.remove_private_constructors=true +sp_cleanup.remove_redundant_type_arguments=false +sp_cleanup.remove_trailing_whitespaces=true +sp_cleanup.remove_trailing_whitespaces_all=true +sp_cleanup.remove_trailing_whitespaces_ignore_empty=false +sp_cleanup.remove_unnecessary_casts=false +sp_cleanup.remove_unnecessary_nls_tags=true +sp_cleanup.remove_unused_imports=true +sp_cleanup.remove_unused_local_variables=false +sp_cleanup.remove_unused_private_fields=true +sp_cleanup.remove_unused_private_members=false +sp_cleanup.remove_unused_private_methods=true +sp_cleanup.remove_unused_private_types=true +sp_cleanup.sort_members=false +sp_cleanup.sort_members_all=false +sp_cleanup.use_anonymous_class_creation=false +sp_cleanup.use_blocks=false +sp_cleanup.use_blocks_only_for_return_and_throw=false +sp_cleanup.use_lambda=false +sp_cleanup.use_parentheses_in_expressions=false +sp_cleanup.use_this_for_non_static_field_access=false +sp_cleanup.use_this_for_non_static_field_access_only_if_necessary=true +sp_cleanup.use_this_for_non_static_method_access=false +sp_cleanup.use_this_for_non_static_method_access_only_if_necessary=true +sp_cleanup.use_type_arguments=false diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.pde.prefs b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.pde.prefs new file mode 100644 index 00000000000..cf80c8bc5b8 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/.settings/org.eclipse.pde.prefs @@ -0,0 +1,32 @@ +compilers.f.unresolved-features=1 +compilers.f.unresolved-plugins=1 +compilers.incompatible-environment=1 +compilers.p.build=1 +compilers.p.build.bin.includes=1 +compilers.p.build.encodings=2 +compilers.p.build.java.compiler=2 +compilers.p.build.java.compliance=1 +compilers.p.build.missing.output=2 +compilers.p.build.output.library=1 +compilers.p.build.source.library=1 +compilers.p.build.src.includes=1 +compilers.p.deprecated=1 +compilers.p.discouraged-class=1 +compilers.p.internal=1 +compilers.p.missing-packages=1 +compilers.p.missing-version-export-package=2 +compilers.p.missing-version-import-package=1 +compilers.p.missing-version-require-bundle=1 +compilers.p.no-required-att=0 +compilers.p.not-externalized-att=2 +compilers.p.unknown-attribute=1 +compilers.p.unknown-class=1 +compilers.p.unknown-element=1 +compilers.p.unknown-identifier=1 +compilers.p.unknown-resource=1 +compilers.p.unresolved-ex-points=0 +compilers.p.unresolved-import=0 +compilers.s.create-docs=false +compilers.s.doc-folder=doc +compilers.s.open-tags=1 +eclipse.preferences.version=1 diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/META-INF/MANIFEST.MF b/terminal/plugins/org.eclipse.tm.terminal.view.ui/META-INF/MANIFEST.MF new file mode 100644 index 00000000000..610381a5c45 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/META-INF/MANIFEST.MF @@ -0,0 +1,40 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: %pluginName +Bundle-SymbolicName: org.eclipse.tm.terminal.view.ui;singleton:=true +Bundle-Version: 4.5.200.qualifier +Bundle-Activator: org.eclipse.tm.terminal.view.ui.activator.UIPlugin +Bundle-Vendor: %providerName +Require-Bundle: org.eclipse.core.expressions;bundle-version="3.4.400", + org.eclipse.core.runtime;bundle-version="3.8.0", + org.eclipse.core.resources;bundle-version="3.8.1";resolution:=optional, + org.eclipse.core.variables;bundle-version="3.2.600", + org.eclipse.debug.ui;bundle-version="3.8.1";resolution:=optional, + org.eclipse.egit.ui;bundle-version="2.0.0";resolution:=optional, + org.eclipse.tm.terminal.view.core;bundle-version="4.5.0", + org.eclipse.tm.terminal.control;bundle-version="4.5.0", + org.eclipse.ui;bundle-version="3.8.0" +Bundle-RequiredExecutionEnvironment: JavaSE-1.6 +Bundle-ActivationPolicy: lazy +Bundle-Localization: plugin +Export-Package: org.eclipse.tm.terminal.view.ui.actions, + org.eclipse.tm.terminal.view.ui.activator;x-internal:=true, + org.eclipse.tm.terminal.view.ui.controls, + org.eclipse.tm.terminal.view.ui.help, + org.eclipse.tm.terminal.view.ui.interfaces, + org.eclipse.tm.terminal.view.ui.interfaces.tracing;x-internal:=true, + org.eclipse.tm.terminal.view.ui.internal;x-internal:=true, + org.eclipse.tm.terminal.view.ui.internal.dialogs;x-internal:=true, + org.eclipse.tm.terminal.view.ui.internal.handler;x-internal:=true, + org.eclipse.tm.terminal.view.ui.launcher, + org.eclipse.tm.terminal.view.ui.listeners, + org.eclipse.tm.terminal.view.ui.local.showin;x-internal:=true, + org.eclipse.tm.terminal.view.ui.manager, + org.eclipse.tm.terminal.view.ui.nls;x-internal:=true, + org.eclipse.tm.terminal.view.ui.panels, + org.eclipse.tm.terminal.view.ui.preferences;x-internal:=true, + org.eclipse.tm.terminal.view.ui.services, + org.eclipse.tm.terminal.view.ui.streams, + org.eclipse.tm.terminal.view.ui.tabs, + org.eclipse.tm.terminal.view.ui.view, + org.eclipse.tm.terminal.view.ui.view.showin;x-internal:=true diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/about.html b/terminal/plugins/org.eclipse.tm.terminal.view.ui/about.html new file mode 100644 index 00000000000..fe4ae3f5b94 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/about.html @@ -0,0 +1,28 @@ + + + + +About + + +

            About This Content

            + +

            May 24, 2012

            +

            License

            + +

            The Eclipse Foundation makes available all content in this plug-in ("Content"). Unless otherwise +indicated below, the Content is provided to you under the terms and conditions of the +Eclipse Public License 2.0 ("EPL"). A copy of the EPL is available +at https://www.eclipse.org/legal/epl-2.0/. +For purposes of the EPL, "Program" will mean the Content.

            + +

            If you did not receive this Content directly from the Eclipse Foundation, the Content is +being redistributed by another party ("Redistributor") and different terms and conditions may +apply to your use of any object code in the Content. Check the Redistributor's license that was +provided with the Content. If no such license exists, contact the Redistributor. Unless otherwise +indicated below, the terms and conditions of the EPL still apply to any source code in the Content +and such source code may be obtained at http://www.eclipse.org.

            + + + \ No newline at end of file diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/build.properties b/terminal/plugins/org.eclipse.tm.terminal.view.ui/build.properties new file mode 100644 index 00000000000..2ac1c658faa --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/build.properties @@ -0,0 +1,21 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### +source.. = src/ +output.. = bin/ +bin.includes = META-INF/,\ + .,\ + plugin.properties,\ + plugin.xml,\ + about.html,\ + icons/,\ + contexts.xml +src.includes = schema/ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/contexts.xml b/terminal/plugins/org.eclipse.tm.terminal.view.ui/contexts.xml new file mode 100644 index 00000000000..7a0390e6408 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/contexts.xml @@ -0,0 +1,22 @@ + + + + + + Select the terminal type and specify the connections settings to connect a new terminal. + + + Select the new encoding for the active terminal. + + + Add or modify an external executable added to the 'Show in Local Terminal' context menu. + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/command_input_field.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/command_input_field.gif new file mode 100644 index 00000000000..9e3a547c145 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/command_input_field.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/lock_co.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/lock_co.png new file mode 100644 index 00000000000..df111d48fb3 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/lock_co.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/lock_co@2x.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/lock_co@2x.png new file mode 100644 index 00000000000..df6d4317702 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/lock_co@2x.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/new_terminal_view.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/new_terminal_view.gif new file mode 100644 index 00000000000..00896268424 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/clcl16/new_terminal_view.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/command_input_field.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/command_input_field.gif new file mode 100644 index 00000000000..f538ca707fc Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/command_input_field.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/disconnect.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/disconnect.gif new file mode 100644 index 00000000000..1ca9213a43c Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/disconnect.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/lock_co.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/lock_co.png new file mode 100644 index 00000000000..6f061961726 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/lock_co.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/lock_co@2x.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/lock_co@2x.png new file mode 100644 index 00000000000..692fa10d326 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/lock_co@2x.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/new_terminal_view.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/new_terminal_view.gif new file mode 100644 index 00000000000..25adc24b2a6 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/dlcl16/new_terminal_view.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/command_input_field.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/command_input_field.gif new file mode 100644 index 00000000000..f538ca707fc Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/command_input_field.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/disconnect.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/disconnect.gif new file mode 100644 index 00000000000..d61dd776e39 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/disconnect.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/lock_co.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/lock_co.png new file mode 100644 index 00000000000..df111d48fb3 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/lock_co.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/lock_co@2x.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/lock_co@2x.png new file mode 100644 index 00000000000..df6d4317702 Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/lock_co@2x.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/new_terminal_view.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/new_terminal_view.gif new file mode 100644 index 00000000000..b81882b503d Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/elcl16/new_terminal_view.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/console_view.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/console_view.png new file mode 100644 index 00000000000..ca77aee5bca Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/console_view.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/console_view@2x.png b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/console_view@2x.png new file mode 100644 index 00000000000..54ecae20f3f Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/console_view@2x.png differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/terminal_view.gif b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/terminal_view.gif new file mode 100644 index 00000000000..bbb6a9e153e Binary files /dev/null and b/terminal/plugins/org.eclipse.tm.terminal.view.ui/icons/eview16/terminal_view.gif differ diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/plugin.properties b/terminal/plugins/org.eclipse.tm.terminal.view.ui/plugin.properties new file mode 100644 index 00000000000..9241281d8b6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/plugin.properties @@ -0,0 +1,75 @@ +################################################################################## +# Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +################################################################################## + +pluginName = Terminal View +providerName = Eclipse.org - Target Management + +# ----- Terminal View ----- + +ViewCategory.name=Terminal + +TerminalsView.name=Terminal +TerminalsView.name.old=Terminals (Old) +TerminalsView.context.name=In Terminal View +TerminalsView.context.description=Show modified keyboard shortcuts in context menu + +# ----- Terminal Connectors ----- + +TerminalConnector.streams=Streams Connector (hidden) + +# ----- Terminal Launcher Delegates ----- + +StreamsLauncherDelegate.label=Streams Terminal + +# ----- Commands and Menu contributions ----- +command.category.name=Terminal Commands + +toolbar.terminal.label=Terminal + +command.launch.selection.name=Open Terminal on Selection +command.launch.name=Open Terminal +command.launch.label=Open Terminal... +command.launch.tooltip=Open a Terminal + +command.disconnect.name=Disconnect Terminal +command.disconnect.label=Disconnect +command.disconnect.tooltip=Disconnect Terminal Connection + +command.newview.name=New Terminal View + +menu.showIn.label = Show in Local Terminal +menu.showIn.mnemonic=I + +LocalLauncherDelegate.label=Local Terminal + +command.launch.name=Open Local Terminal on Selection + +menu.showIn.localterminal.label = Terminal + +TerminalConnector.local=Local + +# ----- Extension Points ----- + +ExtensionPoint.launcherDelegates.name=Terminal Launcher Delegates + +# ----- Activity contributions ----- + +activities.category.terminals.name=Terminal +activities.category.terminals.description=Use the terminal to connect to remote hosts via telnet, ssh and others. + +activities.activity.terminals.views.name=Terminal Views +activities.activity.terminals.views.description=Terminal related views. + +# ----- Preference Pages ----- + +preference.page.name=Local Terminal + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/plugin.xml b/terminal/plugins/org.eclipse.tm.terminal.view.ui/plugin.xml new file mode 100644 index 00000000000..0b61e2c38c5 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/plugin.xml @@ -0,0 +1,480 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/pom.xml b/terminal/plugins/org.eclipse.tm.terminal.view.ui/pom.xml new file mode 100644 index 00000000000..b23790d92b0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/pom.xml @@ -0,0 +1,27 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../../admin/pom-build.xml + + + org.eclipse.tm.terminal.view.ui + 4.5.200-SNAPSHOT + eclipse-plugin + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/schema/launcherDelegates.exsd b/terminal/plugins/org.eclipse.tm.terminal.view.ui/schema/launcherDelegates.exsd new file mode 100644 index 00000000000..4e011a1e3a3 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/schema/launcherDelegates.exsd @@ -0,0 +1,217 @@ + + + + + + + + + This extension point is used to contribute terminal launcher delegates. +<p> +Terminal launcher delegates contributes terminal settings widget to the <code>LaunchTerminalSettingsDialog</code> required to open a remote terminal through a specific communication channel, like TCF or SSH. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Declares a terminal launcher delegate contribution. + + + + + + + + + + + + The unique id of the terminal launcher delegate contribution. + + + + + + + The label representing the terminal launcher delegate within the UI. + + + + + + + The class that implements <code>org.eclipse.tcf.te.ui.terminals.interfaces.ILauncherDelegate</code> or extends <code>org.eclipse.tcf.te.ui.terminals.launcher.AbstractLauncherDelegate</code>. +<p> +The terminal launcher delegate implementation class must be specified either by the class attribute or the class child element! + + + + + + + + + + If <code>true</code>, than the terminal launcher delegate is not visible in the UI, even if a possible <code>enablement</code> will evaluate to <code>true</code>. + + + + + + + + + + A short description of the terminal connector type to be presented in the UI. + + + + + + + + Used when creating an <code>IExecutableExtension</code> with a named parameter, or more than one. + + + + + + + + + + The class that implements <code>org.eclipse.tcf.te.ui.terminals.interfaces.ILauncherDelegate</code> or extends <code>org.eclipse.tcf.te.ui.terminals.launcher.AbstractLauncherDelegate</code>. +<p> +The terminal launcher delegate implementation class must be specified either by the class attribute or the class child element! + + + + + + + + + + + + + A parameter for an <code>IExecutableExtension</code>. + + + + + + + <p>The parameter name.</p> + + + + + + + <p>The parameter value.</p> + + + + + + + + + + + + Target Explorer 1.0.0 + + + + + + + + + This is an example of the extension point usage: +<p> +<pre><code> + <extension point="org.eclipse.tcf.te.ui.terminals.launcherDelegates"> + <delegate + id="org.eclipse.tcf.te.ui.terminals.launcher.tcf" + class="org.eclipse.tcf.te.tcf.terminals.ui.internal.TerminalLauncherDelegate" + label="TCF Terminal"> + <enablement> + ... + </enablement> + </delegate> + </extension> +</code></pre> + + + + + + + + + The provider of a launcher delegate must implement <samp>org.eclipse.tcf.te.ui.terminals.interfaces.ILauncherDelegate</samp>. + + + + + + + + + + Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is +available at https://www.eclipse.org/legal/epl-2.0/ + + SPDX-License-Identifier: EPL-2.0 + + + + diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/AbstractAction.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/AbstractAction.java new file mode 100644 index 00000000000..270c4c468af --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/AbstractAction.java @@ -0,0 +1,191 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.actions; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderToolbarHandler; +import org.eclipse.ui.ISources; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; + +/** + * Abstract terminal action wrapper implementation. + */ +public abstract class AbstractAction extends AbstractTerminalAction { + // Reference to the parent toolbar handler + private final TabFolderToolbarHandler parent; + + /** + * Constructor. + * + * @param parent + * The parent toolbar handler instance. Must not be + * null. + * @param id + * The terminal action id. Must not be null. + */ + public AbstractAction(TabFolderToolbarHandler parent, String id) { + super(id); + + Assert.isNotNull(parent); + this.parent = parent; + } + + /** + * Returns the parent toolbar handler. + * + * @return The parent toolbar handler. + */ + protected final TabFolderToolbarHandler getParent() { + return parent; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getParent().getActiveTerminalViewControl(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#run() + */ + @Override + public void run() { + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)getParent().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + // And execute the command + executeCommand(activeTabItem.getData("customData")); //$NON-NLS-1$ + } + } + } + + /** + * Executes the command for the given data node as current and active menu selection. + *

            + * Node: If the provided data node is null, the method will trigger + * the command with an empty selection. + * + * @param data The terminal custom data node or null. + */ + @SuppressWarnings("cast") + protected void executeCommand(Object data) { + // Get the command service from the workbench + ICommandService service = (ICommandService)PlatformUI.getWorkbench().getAdapter(ICommandService.class); + if (service != null && getCommandId() != null) { + // Get the command + final Command command = service.getCommand(getCommandId()); + if (command != null && command.isDefined()) { + IHandlerService handlerSvc = (IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class); + Assert.isNotNull(handlerSvc); + + // Construct a selection element + IStructuredSelection selection = data != null ? new StructuredSelection(data) : new StructuredSelection(); + // Construct the application context + EvaluationContext context = new EvaluationContext(handlerSvc.getCurrentState(), selection); + // Apply the selection to the "activeMenuSelection" and "selection" variable too + context.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection); + context.addVariable(ISources.ACTIVE_MENU_SELECTION_NAME, selection); + // Allow plug-in activation + context.setAllowPluginActivation(true); + // And execute the event + try { + ParameterizedCommand pCmd = ParameterizedCommand.generateCommand(command, null); + Assert.isNotNull(pCmd); + + handlerSvc.executeCommandInContext(pCmd, null, context); + } catch (Exception e) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.AbstractAction_error_commandExecutionFailed, getCommandId(), e.getLocalizedMessage()), + e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + } + + /** + * Returns the command id of the command to execute. + * + * @return The command id. Must be never null. + */ + protected abstract String getCommandId(); + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + // Ignore the flag given from outside. We have to decide ourself + // what the enabled state of the action is + boolean enabled = getTarget() != null; + + // If a target terminal control is available, we need to find the corresponding + // VLM target object which we need to trigger the handler + if (enabled) { + // The action will be enabled if we can determine the VLM target object + enabled = false; + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)getParent().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + enabled = checkEnableAction(activeTabItem.getData("customData")); //$NON-NLS-1$ + } + } + } + + setEnabled(enabled); + } + + /** + * Checks if the action should be enabled based on the given terminal data object. + * + * @param data The terminal data node or null. + * @return True to enable the action, false otherwise. + */ + protected boolean checkEnableAction(Object data) { + return data != null; + } + + /** + * Returns if the action is a separator. Returning true here + * means that an additional separator toolbar element is added right or + * above of the action. + * + * @return True if the action is separating the parent contribution manager, false otherwise. + */ + public boolean isSeparator() { + return false; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/NewTerminalViewAction.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/NewTerminalViewAction.java new file mode 100644 index 00000000000..583bfad7054 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/NewTerminalViewAction.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.actions; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.action.IAction; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.interfaces.ImageConsts; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; + +/** + * Opens a new terminal view with a new secondary view ID. + * + * @since 4.1 + */ +public class NewTerminalViewAction extends AbstractTerminalAction { + + //private ITerminalsView view = null; + + /** + * Constructor. + */ + public NewTerminalViewAction(ITerminalsView view) { + super(null, NewTerminalViewAction.class.getName(), IAction.AS_PUSH_BUTTON); + + //this.view = view; + setupAction(Messages.NewTerminalViewAction_menu, Messages.NewTerminalViewAction_tooltip, + UIPlugin.getImageDescriptor(ImageConsts.ACTION_NewTerminalView_Hover), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_NewTerminalView_Enabled), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_NewTerminalView_Disabled), true); + setEnabled(true); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#run() + */ + @SuppressWarnings("cast") + @Override + public void run() { + ICommandService service = (ICommandService)PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = service != null ? service.getCommand("org.eclipse.tm.terminal.view.ui.command.newview") : null; //$NON-NLS-1$ + if (command != null && command.isDefined() && command.isEnabled()) { + try { + ParameterizedCommand pCmd = ParameterizedCommand.generateCommand(command, null); + Assert.isNotNull(pCmd); + IHandlerService handlerSvc = (IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class); + Assert.isNotNull(handlerSvc); + handlerSvc.executeCommandInContext(pCmd, null, handlerSvc.getCurrentState()); + } catch (Exception e) { + // If the platform is in debug mode, we print the exception to the log view + if (Platform.inDebugMode()) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + Messages.AbstractTriggerCommandHandler_error_executionFailed, e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java new file mode 100644 index 00000000000..9c416f4292b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/SelectEncodingAction.java @@ -0,0 +1,81 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.actions; + +import java.io.UnsupportedEncodingException; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.window.Window; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.ui.internal.dialogs.EncodingSelectionDialog; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; + +/** + * Terminal control select encoding action implementation. + */ +public class SelectEncodingAction extends AbstractTerminalAction { + // Reference to the parent tab folder manager + private final TabFolderManager tabFolderManager; + + /** + * Constructor. + * + * @param tabFolderManager The parent tab folder manager. Must not be null. + */ + public SelectEncodingAction(TabFolderManager tabFolderManager) { + super(null, SelectEncodingAction.class.getName(), IAction.AS_PUSH_BUTTON); + + Assert.isNotNull(tabFolderManager); + this.tabFolderManager = tabFolderManager; + + setupAction(Messages.SelectEncodingAction_menu, + Messages.SelectEncodingAction_tooltip, + (ImageDescriptor)null, + (ImageDescriptor)null, + (ImageDescriptor)null, + true); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#run() + */ + @Override + public void run() { + ITerminalViewControl target = getTarget(); + if (target == null) return; + + EncodingSelectionDialog dialog = new EncodingSelectionDialog(null); + dialog.setEncoding(target.getEncoding()); + if (dialog.open() == Window.OK) { + try { + target.setEncoding(dialog.getEncoding()); + tabFolderManager.updateStatusLine(); + } + catch (UnsupportedEncodingException e) { e.printStackTrace(); } + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + setEnabled(aboutToShow + && getTarget() != null && getTarget().getState() == TerminalState.CONNECTED); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/TabScrollLockAction.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/TabScrollLockAction.java new file mode 100644 index 00000000000..ada6f713b83 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/TabScrollLockAction.java @@ -0,0 +1,62 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ImageConsts; +import org.eclipse.tm.terminal.view.ui.nls.Messages; + +/** + * Terminal console tab scroll lock action. + */ +public class TabScrollLockAction extends AbstractTerminalAction { + + /** + * Constructor. + */ + public TabScrollLockAction() { + super(null, TabScrollLockAction.class.getName(), IAction.AS_RADIO_BUTTON); + + setupAction(Messages.TabScrollLockAction_text, + Messages.TabScrollLockAction_tooltip, + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ScrollLock_Hover), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ScrollLock_Enabled), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ScrollLock_Disabled), + true); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#run() + */ + @Override + public void run() { + ITerminalViewControl target = getTarget(); + if (target != null) { + target.setScrollLock(!target.isScrollLock()); + setChecked(target.isScrollLock()); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + setEnabled(aboutToShow && getTarget() != null && getTarget().getState() == TerminalState.CONNECTED); + setChecked(getTarget() != null && getTarget().isScrollLock()); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/ToggleCommandFieldAction.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/ToggleCommandFieldAction.java new file mode 100644 index 00000000000..a3a0073f4d7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/actions/ToggleCommandFieldAction.java @@ -0,0 +1,91 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.actions; + +import org.eclipse.jface.action.IAction; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.interfaces.ImageConsts; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.tm.terminal.view.ui.tabs.TabCommandFieldHandler; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; + +/** + * Toggle command input field. + */ +public class ToggleCommandFieldAction extends AbstractTerminalAction { + private ITerminalsView view = null; + + /** + * Constructor. + */ + public ToggleCommandFieldAction(ITerminalsView view) { + super(null, ToggleCommandFieldAction.class.getName(), IAction.AS_CHECK_BOX); + + this.view = view; + setupAction(Messages.ToggleCommandFieldAction_menu, Messages.ToggleCommandFieldAction_toolTip, + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ToggleCommandField_Hover), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ToggleCommandField_Enabled), + UIPlugin.getImageDescriptor(ImageConsts.ACTION_ToggleCommandField_Disabled), true); + + TabCommandFieldHandler handler = getCommandFieldHandler(); + setChecked(handler != null && handler.hasCommandInputField()); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.action.IAction#run() + */ + @Override + public void run() { + TabCommandFieldHandler handler = getCommandFieldHandler(); + if (handler != null) { + handler.setCommandInputField(!handler.hasCommandInputField()); + } + setChecked(handler != null && handler.hasCommandInputField()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + TabCommandFieldHandler handler = getCommandFieldHandler(); + ITerminalViewControl target = getTarget(); + setEnabled(aboutToShow && handler != null + && target != null && target.getState() == TerminalState.CONNECTED); + setChecked(handler != null && handler.hasCommandInputField()); + } + + /** + * Returns the command input field handler for the active tab. + * + * @return The command input field handler or null. + */ + @SuppressWarnings("cast") + protected TabCommandFieldHandler getCommandFieldHandler() { + TabCommandFieldHandler handler = null; + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager)view.getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null && !activeTabItem.isDisposed()) { + handler = manager.getTabCommandFieldHandler(activeTabItem); + } + } + return handler; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/activator/UIPlugin.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/activator/UIPlugin.java new file mode 100644 index 00000000000..54128156f77 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/activator/UIPlugin.java @@ -0,0 +1,262 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.activator; + +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.ImageRegistry; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.core.preferences.ScopedEclipsePreferences; +import org.eclipse.tm.terminal.view.core.tracing.TraceHandler; +import org.eclipse.tm.terminal.view.ui.interfaces.ImageConsts; +import org.eclipse.tm.terminal.view.ui.listeners.WorkbenchWindowListener; +import org.eclipse.tm.terminal.view.ui.view.TerminalsView; +import org.eclipse.tm.terminal.view.ui.view.TerminalsViewMementoHandler; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IViewReference; +import org.eclipse.ui.IWindowListener; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchListener; +import org.eclipse.ui.IWorkbenchWindow; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.plugin.AbstractUIPlugin; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; + +/** + * The activator class controls the plug-in life cycle + */ +public class UIPlugin extends AbstractUIPlugin { + // The shared instance + private static UIPlugin plugin; + // The scoped preferences instance + private static volatile ScopedEclipsePreferences scopedPreferences; + // The trace handler instance + private static volatile TraceHandler traceHandler; + // The workbench listener instance + private IWorkbenchListener listener; + // The global window listener instance + private IWindowListener windowListener; + + /** + * The constructor + */ + public UIPlugin() { + } + + /** + * Returns the shared instance + * + * @return the shared instance + */ + public static UIPlugin getDefault() { + return plugin; + } + + /** + * Convenience method which returns the unique identifier of this plug-in. + */ + public static String getUniqueIdentifier() { + if (getDefault() != null && getDefault().getBundle() != null) { + return getDefault().getBundle().getSymbolicName(); + } + return "org.eclipse.tm.terminal.view.ui"; //$NON-NLS-1$ + } + + /** + * Return the scoped preferences for this plug-in. + */ + public static ScopedEclipsePreferences getScopedPreferences() { + if (scopedPreferences == null) { + scopedPreferences = new ScopedEclipsePreferences(getUniqueIdentifier()); + } + return scopedPreferences; + } + + /** + * Returns the bundles trace handler. + * + * @return The bundles trace handler. + */ + public static TraceHandler getTraceHandler() { + if (traceHandler == null) { + traceHandler = new TraceHandler(getUniqueIdentifier()); + } + return traceHandler; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext) + */ + @Override + public void start(BundleContext context) throws Exception { + super.start(context); + plugin = this; + + // Create and register the workbench listener instance + listener = new IWorkbenchListener() { + + @Override + public boolean preShutdown(IWorkbench workbench, boolean forced) { + if (workbench != null && workbench.getActiveWorkbenchWindow() != null && workbench.getActiveWorkbenchWindow().getActivePage() != null) { + // Find all "Terminal" views + IViewReference[] refs = workbench.getActiveWorkbenchWindow().getActivePage().getViewReferences(); + for (IViewReference ref : refs) { + IViewPart part = ref.getView(false); + if (part instanceof TerminalsView) { + /* + * The terminal tabs to save to the views memento on shutdown can + * be determined only _before_ the saveState(memento) method of the + * view is called. Within saveState, it is already to late and the + * terminals might be in CLOSED state already. This depends on the + * terminal type and the corresponding connector implementation. + * + * To be safe, we determine the still opened terminals on shutdown + * separately here in the preShutdown. + */ + final List saveables = new ArrayList(); + + // Get the tab folder + CTabFolder tabFolder = (CTabFolder)((TerminalsView)part).getAdapter(CTabFolder.class); + if (tabFolder != null && !tabFolder.isDisposed()) { + // Get the list of tab items + CTabItem[] items = tabFolder.getItems(); + // Loop the tab items and find the still connected ones + for (CTabItem item : items) { + // Ignore disposed items + if (item.isDisposed()) continue; + // Get the terminal view control + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal == null || terminal.getState() != TerminalState.CONNECTED) { + continue; + } + // Still connected -> Add to the list + saveables.add(item); + } + } + + // Push the determined saveable items to the memento handler + TerminalsViewMementoHandler mementoHandler = (TerminalsViewMementoHandler)((TerminalsView)part).getAdapter(TerminalsViewMementoHandler.class); + if (mementoHandler != null) mementoHandler.setSaveables(saveables); + } + } + } + + return true; + } + + @Override + public void postShutdown(IWorkbench workbench) { + } + }; + PlatformUI.getWorkbench().addWorkbenchListener(listener); + + if (windowListener == null && PlatformUI.getWorkbench() != null) { + windowListener = new WorkbenchWindowListener(); + PlatformUI.getWorkbench().addWindowListener(windowListener); + activateContexts(); + } + } + + void activateContexts() { + if (Display.getCurrent() != null) { + IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); + if (window != null && windowListener != null) windowListener.windowOpened(window); + } + else { + PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable(){ + @Override + public void run() { + activateContexts(); + }}); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext) + */ + @Override + public void stop(BundleContext context) throws Exception { + if (windowListener != null && PlatformUI.getWorkbench() != null) { + PlatformUI.getWorkbench().removeWindowListener(windowListener); + windowListener = null; + } + + plugin = null; + scopedPreferences = null; + traceHandler = null; + if (listener != null) { PlatformUI.getWorkbench().removeWorkbenchListener(listener); listener = null; } + super.stop(context); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.plugin.AbstractUIPlugin#initializeImageRegistry(org.eclipse.jface.resource.ImageRegistry) + */ + @Override + protected void initializeImageRegistry(ImageRegistry registry) { + Bundle bundle = getBundle(); + URL url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_EVIEW + "console_view.png"); //$NON-NLS-1$ + registry.put(ImageConsts.VIEW_Terminals, ImageDescriptor.createFromURL(url)); + + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_CLCL + "lock_co.png"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_ScrollLock_Hover, ImageDescriptor.createFromURL(url)); + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_ELCL + "lock_co.png"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_ScrollLock_Enabled, ImageDescriptor.createFromURL(url)); + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_DLCL + "lock_co.png"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_ScrollLock_Disabled, ImageDescriptor.createFromURL(url)); + + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_CLCL + "command_input_field.gif"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_ToggleCommandField_Hover, ImageDescriptor.createFromURL(url)); + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_ELCL + "command_input_field.gif"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_ToggleCommandField_Enabled, ImageDescriptor.createFromURL(url)); + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_DLCL + "command_input_field.gif"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_ToggleCommandField_Disabled, ImageDescriptor.createFromURL(url)); + + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_CLCL + "new_terminal_view.gif"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_NewTerminalView_Hover, ImageDescriptor.createFromURL(url)); + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_ELCL + "new_terminal_view.gif"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_NewTerminalView_Enabled, ImageDescriptor.createFromURL(url)); + url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_DLCL + "new_terminal_view.gif"); //$NON-NLS-1$ + registry.put(ImageConsts.ACTION_NewTerminalView_Disabled, ImageDescriptor.createFromURL(url)); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the Image object instance. + * + * @param key The key the image is registered with. + * @return The Image object instance or null. + */ + public static Image getImage(String key) { + return getDefault().getImageRegistry().get(key); + } + + /** + * Loads the image registered under the specified key from the image + * registry and returns the ImageDescriptor object instance. + * + * @param key The key the image is registered with. + * @return The ImageDescriptor object instance or null. + */ + public static ImageDescriptor getImageDescriptor(String key) { + return getDefault().getImageRegistry().getDescriptor(key); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/controls/ConfigurationPanelControl.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/controls/ConfigurationPanelControl.java new file mode 100644 index 00000000000..d5941ccae69 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/controls/ConfigurationPanelControl.java @@ -0,0 +1,423 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.controls; + +import java.util.HashMap; +import java.util.Hashtable; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.StackLayout; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel; + +/** + * Base control to deal with wizard or property page controls + * which should share the same UI space. + */ +public class ConfigurationPanelControl implements IConfigurationPanelContainer, IMessageProvider { + private final Map configurationPanels = new Hashtable(); + + private String message = null; + private int messageType = IMessageProvider.NONE; + + private boolean isGroup; + + private Composite panel; + private StackLayout panelLayout; + + private String activeConfigurationPanelKey = null; + private IConfigurationPanel activeConfigurationPanel = null; + + private final AbstractConfigurationPanel EMPTY_PANEL; + + /** + * An empty configuration panel implementation. + */ + private static final class EmptySettingsPanel extends AbstractConfigurationPanel { + + /** + * Constructor. + * + * @param container The configuration panel container or null. + */ + public EmptySettingsPanel(IConfigurationPanelContainer container) { + super(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupPanel(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + panel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + + panel.setBackground(parent.getBackground()); + + setControl(panel); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#isValid() + */ + @Override + public boolean isValid() { + return false; + } + } + + /** + * Cleanup all resources the control might have been created. + */ + public void dispose() { + EMPTY_PANEL.dispose(); + } + + /** + * Constructor. + */ + public ConfigurationPanelControl() { + EMPTY_PANEL = new EmptySettingsPanel(this); + clear(); + setPanelIsGroup(false); + } + + /** + * Sets if or if not the controls panel is a Group. + * + * @param isGroup True if the controls panel is a group, false otherwise. + */ + public void setPanelIsGroup(boolean isGroup) { + this.isGroup = isGroup; + } + + /** + * Returns if or if not the controls panel is a Group. + * + * @return True if the controls panel is a group, false otherwise. + */ + public boolean isPanelIsGroup() { + return isGroup; + } + + /** + * Returns the controls panel. + * + * @return The controls panel or null. + */ + public Composite getPanel() { + return panel; + } + + /** + * Returns the label text to set for the group (if the panel is a group). + * + * @return The label text to apply or null. + */ + public String getGroupLabel() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer#validate() + */ + @Override + public void validate() { + } + + /** + * To be called from the embedding control to setup the controls UI elements. + * + * @param parent The parent control. Must not be null! + */ + public void setupPanel(Composite parent, String[] configurationPanelKeys) { + Assert.isNotNull(parent); + + if (isPanelIsGroup()) { + panel = new Group(parent, SWT.NONE); + if (getGroupLabel() != null) ((Group)panel).setText(getGroupLabel()); + } else { + panel = new Composite(parent, SWT.NONE); + } + Assert.isNotNull(panel); + panel.setFont(parent.getFont()); + panel.setBackground(parent.getBackground()); + + panelLayout = new StackLayout(); + panel.setLayout(panelLayout); + + setupConfigurationPanels(panel, configurationPanelKeys); + EMPTY_PANEL.setupPanel(panel); + } + + /** + * Removes all configuration panels. + */ + public void clear() { + configurationPanels.clear(); + } + + /** + * Returns a unsorted list of all registered configuration panel id's. + * + * @return A list of registered configuration panel id's. + */ + public String[] getConfigurationPanelIds() { + return configurationPanels.keySet().toArray(new String[configurationPanels.keySet().size()]); + } + + /** + * Returns the configuration panel instance registered for the given configuration panel key. + * + * @param key The key to get the configuration panel for. Must not be null! + * @return The configuration panel instance or an empty configuration panel if the key is unknown. + */ + public IConfigurationPanel getConfigurationPanel(String key) { + IConfigurationPanel panel = key != null ? configurationPanels.get(key) : null; + return panel != null ? panel : EMPTY_PANEL; + } + + /** + * Returns if or if not the given configuration panel is equal to the + * empty configuration panel. + * + * @param panel The configuration panel or null. + * @return True if the configuration panel is equal to the empty configuration panel. + */ + public final boolean isEmptyConfigurationPanel(IConfigurationPanel panel) { + return EMPTY_PANEL == panel; + } + + /** + * Adds the given configuration panel under the given configuration panel key to the + * list of known panels. If the given configuration panel is null, any + * configuration panel stored under the given key is removed from the list of known panels. + * + * @param key The key to get the configuration panel for. Must not be null! + * @param panel The configuration panel instance or null. + */ + public void addConfigurationPanel(String key, IConfigurationPanel panel) { + if (key == null) return; + if (panel != null) { + configurationPanels.put(key, panel); + } else { + configurationPanels.remove(key); + } + } + + /** + * Setup the configuration panels for being presented to the user. This method is called by the + * controls doSetupPanel(...) and initialize all possible configuration panels to show. + * The default implementation iterates over the given list of configuration panel keys and calls + * setupPanel(...) for each of them. + * + * @param parent The parent composite to use for the configuration panels. Must not be null! + * @param configurationPanelKeys The list of configuration panels to initialize. Might be null or empty! + */ + public void setupConfigurationPanels(Composite parent, String[] configurationPanelKeys) { + Assert.isNotNull(parent); + + if (configurationPanelKeys != null) { + for (String configurationPanelKey : configurationPanelKeys) { + IConfigurationPanel configPanel = getConfigurationPanel(configurationPanelKey); + Assert.isNotNull(configPanel); + configPanel.setupPanel(parent); + } + } + } + + /** + * Make the wizard configuration panel registered under the given configuration panel key the + * most top configuration panel. If no configuration panel is registered under the given key, + * nothing will happen. + * + * @param key The key to get the wizard configuration panel for. Must not be null! + */ + public void showConfigurationPanel(String key) { + String activeKey = getActiveConfigurationPanelKey(); + if (key != null && key.equals(activeKey) && activeConfigurationPanel != null) { + return; + } + IConfigurationPanel configPanel = getActiveConfigurationPanel(); + Map data = new HashMap(); + if (configPanel != null) configPanel.extractData(data); + configPanel = getConfigurationPanel(key); + Assert.isNotNull(configPanel); + if (configPanel.getControl() != null) { + activeConfigurationPanel = configPanel; + activeConfigurationPanelKey = key; + panelLayout.topControl = configPanel.getControl(); + panel.layout(); + if (!data.isEmpty()) configPanel.updateData(data); + configPanel.activate(); + } + else { + activeConfigurationPanelKey = key; + } + } + + /** + * Returns the currently active configuration panel. + * + * @return The active configuration panel or null. + */ + public IConfigurationPanel getActiveConfigurationPanel() { + return activeConfigurationPanel; + } + + /** + * Returns the currently active configuration panel key. + * + * @return The active configuration panel key or null. + */ + public String getActiveConfigurationPanelKey() { + return activeConfigurationPanelKey; + } + + /** + * Returns the dialog settings to use to save and restore control specific + * widget values. + * + * @param settings The parent dialog settings. Must not be null. + * @return The dialog settings to use. + */ + public final IDialogSettings getDialogSettings(IDialogSettings settings) { + Assert.isNotNull(settings); + + // Store the settings of the control within it's own section. + String sectionName = this.getClass().getSimpleName(); + Assert.isNotNull(sectionName); + + IDialogSettings section = settings.getSection(sectionName); + if (section == null) { + section = settings.addNewSection(sectionName); + } + + return section; + } + + /** + * Restore the widget values from the dialog settings store to recreate the control history. + *

            + * Note: + * The control is saving the widget values into a section equal to the class name {@link Class#getName()}. + * After the sections has been created, the method calls doRestoreWidgetValues for restoring + * the single properties from the dialog settings. Subclasses may override doRestoreWidgetValues + * only to deal with the single properties only or restoreWidgetValues when to override the + * creation of the subsections. + * + * @param settings The dialog settings object instance to restore the widget values from. Must not be null! + * @param idPrefix The prefix to use for every dialog settings slot keys. If null, the dialog settings slot keys are not to prefix. + */ + public final void restoreWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + // now, call the hook for actually reading the single properties from the dialog settings. + doRestoreWidgetValues(getDialogSettings(settings), idPrefix); + } + + /** + * Hook to restore the widget values finally plain from the given dialog settings. This method should + * not fragment the given dialog settings any further. + * + * @param settings The dialog settings to restore the widget values from. Must not be null! + * @param idPrefix The prefix to use for every dialog settings slot keys. If null, the dialog settings slot keys are not to prefix. + */ + public void doRestoreWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + for (String panelKey : configurationPanels.keySet()) { + IConfigurationPanel configPanel = getConfigurationPanel(panelKey); + if (configPanel != null && !isEmptyConfigurationPanel(configPanel)) { + IDialogSettings configPanelSettings = settings.getSection(panelKey); + if (configPanelSettings == null) configPanelSettings = settings.addNewSection(panelKey); + configPanel.doRestoreWidgetValues(configPanelSettings, idPrefix); + } + } + } + + /** + * Saves the widget values to the dialog settings store for remembering the history. The control might + * be embedded within multiple pages multiple times handling different properties. Because the single + * controls should not mix up the history, we create subsections within the given dialog settings if + * they do not already exist. After the sections has been created, the method calls doSaveWidgetValues + * for saving the single properties to the dialog settings. Subclasses may override doSaveWidgetValues + * only to deal with the single properties only or saveWidgetValues when to override the + * creation of the subsections. + * + * @param settings The dialog settings object instance to save the widget values to. Must not be null! + * @param idPrefix The prefix to use for every dialog settings slot keys. If null, the dialog settings slot keys are not to prefix. + */ + public final void saveWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + // now, call the hook for actually writing the single properties to the dialog settings. + doSaveWidgetValues(getDialogSettings(settings), idPrefix); + } + + /** + * Hook to save the widget values finally plain to the given dialog settings. This method should + * not fragment the given dialog settings any further. + * + * @param settings The dialog settings to save the widget values to. Must not be null! + * @param idPrefix The prefix to use for every dialog settings slot keys. If null, the dialog settings slot keys are not to prefix. + */ + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + IConfigurationPanel configPanel = getActiveConfigurationPanel(); + if (configPanel != null && !isEmptyConfigurationPanel(configPanel)) { + String key = getActiveConfigurationPanelKey(); + IDialogSettings configPanelSettings = settings.getSection(key); + if (configPanelSettings == null) configPanelSettings = settings.addNewSection(key); + configPanel.doSaveWidgetValues(configPanelSettings, idPrefix); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessage() + */ + @Override + public final String getMessage() { + return message; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessageType() + */ + @Override + public final int getMessageType() { + return messageType; + } + + /** + * Set the message and the message type to display. + * + * @param message The message or null. + * @param messageType The message type or IMessageProvider.NONE. + */ + @Override + public final void setMessage(String message, int messageType) { + this.message = message; + this.messageType = messageType; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/controls/NoteCompositeHelper.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/controls/NoteCompositeHelper.java new file mode 100644 index 00000000000..efaf2fcfa82 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/controls/NoteCompositeHelper.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.controls; + +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.jface.util.PropertyChangeEvent; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.graphics.Font; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tm.terminal.view.ui.nls.Messages; + +/** + * A helper class to create a composite with a highlighted note + * entry and a message text. + */ +public class NoteCompositeHelper { + + /** + * The common label text to show on a note. Defaults to "Note:". + */ + public static final String NOTE_LABEL = Messages.NoteCompositeHelper_note_label; + + private static class NoteComposite extends Composite { + + public NoteComposite(Composite parent, int style) { + super(parent, style); + } + + @Override + public void setEnabled(boolean enabled) { + super.setEnabled(enabled); + for (Control child : getChildren()) { + child.setEnabled(enabled); + } + } + } + + /** + * Creates a composite with a highlighted Note entry and a message text. + * This is designed to take up the full width of the page. + * + * @see PreferencePage#createNoteComposite, this is a plain copy of that! + * @param font + * the font to use + * @param composite + * the parent composite + * @param title + * the title of the note + * @param message + * the message for the note + * + * @return the composite for the note + */ + public static Composite createNoteComposite(Font font, Composite composite, String title, String message) { + return createNoteComposite(font, composite, title, message, SWT.DEFAULT); + } + + /** + * Creates a composite with a highlighted Note entry and a message text. + * This is designed to take up the full width of the page. + * + * @see PreferencePage#createNoteComposite, this is a plain copy of that! + * @param font + * the font to use + * @param composite + * the parent composite + * @param title + * the title of the note + * @param message + * the message for the note + * @param minCharsPerLine + * the minimum number of characters per line. Defaults to '65' if less than '20'. + * + * @return the composite for the note + */ + public static Composite createNoteComposite(Font font, Composite composite, String title, String message, int minCharsPerLine) { + final GC gc = new GC(composite); + gc.setFont(font); + + Composite messageComposite = new NoteComposite(composite, SWT.NONE); + + GridLayout messageLayout = new GridLayout(); + messageLayout.numColumns = 2; + messageLayout.marginWidth = 0; + messageLayout.marginHeight = 0; + messageComposite.setLayout(messageLayout); + + GridData layoutData = new GridData(GridData.HORIZONTAL_ALIGN_FILL); + if (composite.getLayout() instanceof GridLayout) { + layoutData.horizontalSpan = ((GridLayout) composite.getLayout()).numColumns; + } + messageComposite.setLayoutData(layoutData); + messageComposite.setFont(font); + + final Label noteLabel = new Label(messageComposite, SWT.BOLD); + noteLabel.setText(title); + noteLabel.setFont(JFaceResources.getFontRegistry().getBold(JFaceResources.DEFAULT_FONT)); + noteLabel.setLayoutData(new GridData(GridData.VERTICAL_ALIGN_BEGINNING)); + + final IPropertyChangeListener fontListener = new IPropertyChangeListener() { + @Override + public void propertyChange(PropertyChangeEvent event) { + // Note: This is actually wrong but the same as in platforms + // PreferencePage + if (JFaceResources.BANNER_FONT.equals(event.getProperty())) { + noteLabel.setFont(JFaceResources.getFont(JFaceResources.BANNER_FONT)); + } + } + }; + JFaceResources.getFontRegistry().addListener(fontListener); + noteLabel.addDisposeListener(new DisposeListener() { + @Override + public void widgetDisposed(DisposeEvent event) { + JFaceResources.getFontRegistry().removeListener(fontListener); + } + }); + + Label messageLabel = new Label(messageComposite, SWT.WRAP); + messageLabel.setText(message); + messageLabel.setFont(font); + + /** + * Set the controls style to FILL_HORIZONTAL making it multi-line if + * needed + */ + layoutData = new GridData(GridData.FILL_HORIZONTAL); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), minCharsPerLine >= 20 ? minCharsPerLine : 65); + messageLabel.setLayoutData(layoutData); + + gc.dispose(); + + return messageComposite; + } + + /** + * change the text of the second label + * + * @param messageComposite + * the NoteComposite that gets returned from createNoteComposite + * @param msg + * the new text + */ + public static void setMessage(Composite messageComposite, String msg) { + if (messageComposite instanceof NoteComposite) { + Control[] children = messageComposite.getChildren(); + if (children.length == 2) { + Control c = children[1]; + if (c instanceof Label) { + ((Label) c).setText(msg); + messageComposite.pack(); + } + } + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/help/IContextHelpIds.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/help/IContextHelpIds.java new file mode 100644 index 00000000000..4576584de18 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/help/IContextHelpIds.java @@ -0,0 +1,46 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.help; + +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; + + +/** + * UI Context help id definitions. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IContextHelpIds { + + /** + * UI plug-in common context help id prefix. + */ + public final static String PREFIX = UIPlugin.getUniqueIdentifier() + "."; //$NON-NLS-1$ + + /** + * Launch terminal settings dialog. + */ + public final static String LAUNCH_TERMINAL_SETTINGS_DIALOG = PREFIX + "LaunchTerminalSettingsDialog"; //$NON-NLS-1$ + + /** + * Terminal control encoding selection dialog. + */ + public final static String ENCODING_SELECTION_DIALOG = PREFIX + "EncodingSelectionDialog"; //$NON-NLS-1$ + + /** + * External executables dialog. + * @since 4.1 + */ + public final static String EXTERNAL_EXECUTABLES_DIALOG = PREFIX + "ExternalExecutablesDialog"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IConfigurationPanel.java new file mode 100644 index 00000000000..23859039434 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IConfigurationPanel.java @@ -0,0 +1,146 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +import java.util.Map; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel; + +/** + * Terminal launcher configuration panel. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * Clients should extend {@link AbstractConfigurationPanel} instead. + */ +public interface IConfigurationPanel extends IMessageProvider { + + /** + * Returns the configuration panel container. + * + * @return The configuration panel container or null. + */ + public IConfigurationPanelContainer getContainer(); + + /** + * Creates the terminal launcher configuration panel UI elements within the + * given parent composite. Terminal launcher configuration panels should always + * create another composite within the given composite, which is the panel top + * control. The top control is queried later from the stack layout to show the + * different panels if the selected terminal launcher changed. + * + * @param parent The parent composite to create the UI elements in. Must not be null. + */ + public void setupPanel(Composite parent); + + /** + * Cleanup all resources the wizard configuration panel might have been created. + */ + public void dispose(); + + /** + * Returns the terminal launcher configuration panels top control, typically a + * composite control. This control is requested every time the stack layout is + * required to set a new top control because the selected terminal launcher changed. + * + * @return The top control or null if the configuration panel has been not setup yet. + */ + public Composite getControl(); + + /** + * Validates the control and sets the message text and type so the parent + * page or control is able to display validation result informations. + * The default implementation of this method does nothing. + * + * @return Result of validation. + */ + public boolean isValid(); + + /** + * Restore the widget values plain from the given dialog settings. This method should + * not fragment the given dialog settings any further. + * + * @param settings The dialog settings to restore the widget values from. Must not be null! + * @param idPrefix The prefix to use for every dialog settings slot keys. If null, the dialog settings slot keys are not to prefix. + */ + public void doRestoreWidgetValues(IDialogSettings settings, String idPrefix); + + /** + * Save the widget values plain to the given dialog settings. This method should + * not fragment the given dialog settings any further. + * + * @param settings The dialog settings to save the widget values to. Must not be null! + * @param idPrefix The prefix to use for every dialog settings slot keys. If null, the dialog settings slot keys are not to prefix. + */ + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix); + + /** + * Enables or disables all UI elements belonging to the wizard configuration panel. + * + * @param enabled True to enable the UI elements, false otherwise. + */ + public void setEnabled(boolean enabled); + + /** + * Called when the panel gets the active panel. + */ + public void activate(); + + /** + * Initialize the widgets based of the data from the given map. + *

            + * This method may called multiple times during the lifetime of the panel and the given + * map might be even null. + * + * @param data The map or null. + */ + public void setupData(Map data); + + /** + * Extract the data from the widgets and write it back to the given map. + *

            + * This method may called multiple times during the lifetime of the panel and the given + * map might be even null. + * + * @param data The map or null. + */ + public void extractData(Map data); + + /** + * Update the data from the given properties container which contains the current + * working data. + *

            + * This method may called multiple times during the lifetime of the panel and the given + * map might be even null. + * + * @param data The map or null. + */ + public void updateData(Map data); + + /** + * Set the selection to the terminal launcher configuration panel. + * + * @param selection The selection or null. + */ + public void setSelection(ISelection selection); + + /** + * Returns the selection associated with the terminal launcher configuration panel. + * + * @return The selection or null. + */ + public ISelection getSelection(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IConfigurationPanelContainer.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IConfigurationPanelContainer.java new file mode 100644 index 00000000000..aa04b1246b1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IConfigurationPanelContainer.java @@ -0,0 +1,40 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + + + +/** + * A container to deal with configuration panels. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IConfigurationPanelContainer { + + /** + * Validates the container status. + *

            + * If necessary, set the corresponding messages and message types to signal when some sub + * elements of the container needs user attention. + */ + public void validate(); + + /** + * Set the message and the message type to display. + * + * @param message The message or null. + * @param messageType The message type or IMessageProvider.NONE. + */ + public void setMessage(String message, int messageType); + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IExternalExecutablesProperties.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IExternalExecutablesProperties.java new file mode 100644 index 00000000000..3b4507e7469 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IExternalExecutablesProperties.java @@ -0,0 +1,47 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Dirk Fauth - [460496] Moved from o.e.tm.t.connector.local.showin.interfaces + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +/** + * External executables data property names. + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * @since 4.1 + */ +public interface IExternalExecutablesProperties { + + /** + * The name/label of the external executable. + */ + public final String PROP_NAME = "Name"; //$NON-NLS-1$ + + /** + * The absolute path of the external executable. + */ + public final String PROP_PATH = "Path"; //$NON-NLS-1$ + + /** + * The arguments to pass to the external executable. + */ + public final String PROP_ARGS = "Args"; //$NON-NLS-1$ + + /** + * The absolute path to the icon representing the external executable. + */ + public final String PROP_ICON = "Icon"; //$NON-NLS-1$ + + /** + * If set, backslashes are translated to forward slashes on paste. + */ + public final String PROP_TRANSLATE = "Translate"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ILauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ILauncherDelegate.java new file mode 100644 index 00000000000..7cd9990dd4d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ILauncherDelegate.java @@ -0,0 +1,99 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +import java.util.Map; + +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IExecutableExtension; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +/** + * Terminal launcher delegate. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + * Clients should extend {@link AbstractLauncherDelegate} instead. + */ +public interface ILauncherDelegate extends IExecutableExtension, IAdaptable { + + /** + * Returns the unique id of the launcher delegate. The returned + * id must be never null or an empty string. + * + * @return The unique id. + */ + public String getId(); + + /** + * Returns the label or UI name of the launcher delegate. + * + * @return The label or UI name. An empty string if not set. + */ + public String getLabel(); + + /** + * Returns if or if not the launcher delegate is hidden for the user. + * + * @return True if the launcher delegate is hidden, false otherwise. + */ + public boolean isHidden(); + + /** + * Returns the enablement expression. + * + * @return The enablement expression or null. + */ + public Expression getEnablement(); + + /** + * Returns if or if not the user needs to set configuration details for this launcher to work. + * The settings to configure are provided to the user through the configuration panel returned + * by {@link #getPanel(BaseDialogPageControl)}. + * + * @return True if a user configuration is required, false otherwise. + */ + public boolean needsUserConfiguration(); + + /** + * Returns the configuration panel instance to present to the user. The instance must be always + * the same on subsequent calls until disposed. + *

            + * The method may return null if the launcher does not provide any user + * configurable settings. In this case, {@link #needsUserConfiguration()} should return + * false. + * + * @param container The configuration panel container or null. + * @return The configuration panel instance or null + */ + public IConfigurationPanel getPanel(IConfigurationPanelContainer container); + + /** + * Execute the terminal launch. + * + * @param properties The properties. Must not be null. + * @param done The callback or null. + */ + public void execute(Map properties, ITerminalService.Done done); + + /** + * Creates the terminal connector for this launcher delegate based on + * the given properties. + * + * @param properties The terminal properties. Must not be null. + * @return The terminal connector or null. + */ + public ITerminalConnector createTerminalConnector(Map properties); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IMementoHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IMementoHandler.java new file mode 100644 index 00000000000..79f15857579 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IMementoHandler.java @@ -0,0 +1,38 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +import java.util.Map; + +import org.eclipse.ui.IMemento; + +/** + * Terminal properties memento handler. + */ +public interface IMementoHandler { + + /** + * Saves the terminal properties in the given memento. + * + * @param memento The memento. Must not be null. + * @param properties The map containing the terminal properties to save. Must not be null. + */ + public void saveState(IMemento memento, Map properties); + + /** + * Restore the terminal properties from the given memento. + * + * @param memento The memento. Must not be null. + * @param properties The map receiving the restored terminal properties. Must not be null. + */ + public void restoreState(IMemento memento, Map properties); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IPreferenceKeys.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IPreferenceKeys.java new file mode 100644 index 00000000000..fa0245c9c7a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IPreferenceKeys.java @@ -0,0 +1,69 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +/** + * Terminal plug-in preference key definitions. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IPreferenceKeys { + /** + * Preference keys family prefix. + */ + public final String PREF_TERMINAL = "terminals"; //$NON-NLS-1$ + + /** + * Preference key: Remove terminated terminals when a new terminal is created. + */ + public final String PREF_REMOVE_TERMINATED_TERMINALS = PREF_TERMINAL + ".removeTerminatedTerminals"; //$NON-NLS-1$ + + // showin preferences + + /** + * Preference key: Local terminal initial working directory. + * @since 4.1 + */ + public final String PREF_LOCAL_TERMINAL_INITIAL_CWD = PREF_TERMINAL + ".localTerminalInitialCwd"; //$NON-NLS-1$ + + /** + * Preference value: Local terminal initial working directory is "User home" + * @since 4.1 + */ + public final String PREF_INITIAL_CWD_USER_HOME = "userhome"; //$NON-NLS-1$ + + /** + * Preference value: Local terminal initial working directory is "Eclipse home" + * @since 4.1 + */ + public final String PREF_INITIAL_CWD_ECLIPSE_HOME = "eclipsehome"; //$NON-NLS-1$ + + /** + * Preference value: Local terminal initial working directory is "Eclipse workspace" + * @since 4.1 + */ + public final String PREF_INITIAL_CWD_ECLIPSE_WS = "eclipsews"; //$NON-NLS-1$ + + /** + * Preference key: Local terminal default shell command on Unix hosts. + * @since 4.1 + */ + public final String PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX = PREF_TERMINAL + ".localTerminalDefaultShellUnix"; //$NON-NLS-1$ + + /** + * Preference key: Local terminal default shell command arguments on Unix hosts. + * @since 4.1 + */ + public final String PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX_ARGS = PREF_TERMINAL + ".localTerminalDefaultShellUnixArgs"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ITerminalsView.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ITerminalsView.java new file mode 100644 index 00000000000..4d6f6750490 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ITerminalsView.java @@ -0,0 +1,42 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +import org.eclipse.ui.IViewPart; + +/** + * Terminal view public interface. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITerminalsView extends IViewPart { + + /** + * Switch to the empty page control. + */ + public void switchToEmptyPageControl(); + + /** + * Switch to the tab folder control. + */ + public void switchToTabFolderControl(); + + /** + * Returns the context help id associated with the terminal + * console view instance. + * + * @return The context help id or null if none is associated. + */ + public String getContextHelpId(); +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IUIConstants.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IUIConstants.java new file mode 100644 index 00000000000..e18dcbef38a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/IUIConstants.java @@ -0,0 +1,26 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +/** + * Terminal common UI constants. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface IUIConstants { + /** + * The view id of the terminals view. + */ + public static final String ID = "org.eclipse.tm.terminal.view.ui.TerminalsView"; //$NON-NLS-1$ + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ImageConsts.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ImageConsts.java new file mode 100644 index 00000000000..17d24111da2 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/ImageConsts.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces; + +/** + * Image registry constants. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ImageConsts { + /** + * The root directory where to load the images from, relative to + * the bundle directory. + */ + public final static String IMAGE_DIR_ROOT = "icons/"; //$NON-NLS-1$ + + /** + * The directory where to load colored local toolbar images from, + * relative to the image root directory. + */ + public final static String IMAGE_DIR_CLCL = "clcl16/"; //$NON-NLS-1$ + + /** + * The directory where to load disabled local toolbar images from, + * relative to the image root directory. + */ + public final static String IMAGE_DIR_DLCL = "dlcl16/"; //$NON-NLS-1$ + + /** + * The directory where to load enabled local toolbar images from, + * relative to the image root directory. + */ + public final static String IMAGE_DIR_ELCL = "elcl16/"; //$NON-NLS-1$ + + /** + * The directory where to load view related images from, relative to + * the image root directory. + */ + public final static String IMAGE_DIR_EVIEW = "eview16/"; //$NON-NLS-1$ + + /** + * The key to access the terminals console view image. + */ + public static final String VIEW_Terminals = "TerminalsView"; //$NON-NLS-1$ + + /** + * The key to access the scroll lock action image (enabled). + */ + public static final String ACTION_ScrollLock_Enabled = "ScrollLockAction_enabled"; //$NON-NLS-1$ + + /** + * The key to access the scroll lock action image (disabled). + */ + public static final String ACTION_ScrollLock_Disabled = "ScrollLockAction_disabled"; //$NON-NLS-1$ + + /** + * The key to access the scroll lock action image (hover). + */ + public static final String ACTION_ScrollLock_Hover = "ScrollLockAction_hover"; //$NON-NLS-1$ + + /** + * The key to access the new terminal view action image (enabled). + * @since 4.1 + */ + public static final String ACTION_NewTerminalView_Enabled = "NewTerminalViewAction_enabled"; //$NON-NLS-1$ + + /** + * The key to access the new terminal view action image (disabled). + * @since 4.1 + */ + public static final String ACTION_NewTerminalView_Disabled = "NewTerminalViewAction_disabled"; //$NON-NLS-1$ + + /** + * The key to access the new terminal view action image (hover). + * @since 4.1 + */ + public static final String ACTION_NewTerminalView_Hover = "NewTerminalViewAction_hover"; //$NON-NLS-1$ + + /** + * The key to access the toggle command field action image (enabled). + */ + public static final String ACTION_ToggleCommandField_Enabled = "ToggleCommandField_enabled"; //$NON-NLS-1$ + + /** + * The key to access the toggle command field action image (disabled). + */ + public static final String ACTION_ToggleCommandField_Disabled = "ToggleCommandField_disabled"; //$NON-NLS-1$ + + /** + * The key to access the toggle command field action image (hover). + */ + public static final String ACTION_ToggleCommandField_Hover = "ToggleCommandField_hover"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/tracing/ITraceIds.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/tracing/ITraceIds.java new file mode 100644 index 00000000000..d4062007595 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/interfaces/tracing/ITraceIds.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.interfaces.tracing; + +/** + * Core plug-in trace slot identifiers. + * + * @noextend This interface is not intended to be extended by clients. + * @noimplement This interface is not intended to be implemented by clients. + */ +public interface ITraceIds { + + /** + * If activated, tracing information about the terminals output stream monitor is printed out. + */ + public static final String TRACE_OUTPUT_STREAM_MONITOR = "trace/outputStreamMonitor"; //$NON-NLS-1$ + + /** + * If activated, tracing information about the launch terminal command handler is printed out. + */ + public static final String TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER = "trace/launchTerminalCommandHandler"; //$NON-NLS-1$ +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/ExternalExecutablesState.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/ExternalExecutablesState.java new file mode 100644 index 00000000000..d259cbc9c38 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/ExternalExecutablesState.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2016, 2018 Dirk Fauth and others. All rights reserved. + * This program and the accompanying materials are made available under the terms + * of the Eclipse Public License 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Dirk Fauth - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.tm.terminal.view.ui.local.showin.ExternalExecutablesManager; +import org.eclipse.ui.AbstractSourceProvider; +import org.eclipse.ui.ISources; + +/** + * SourceProvider that provides a state to determine whether external executables are configured or not. + */ +public class ExternalExecutablesState extends AbstractSourceProvider { + public final static String CONFIGURED_STATE = "org.eclipse.tm.terminal.external.executable.configured"; //$NON-NLS-1$ + private boolean enabled; + + public ExternalExecutablesState() { + List> externals = ExternalExecutablesManager.load(); + this.enabled = (externals != null && !externals.isEmpty()); + } + + @Override + public String[] getProvidedSourceNames() { + return new String[] { CONFIGURED_STATE }; + } + + @Override + public Map getCurrentState() { + Map map = new HashMap(1); + map.put(CONFIGURED_STATE, Boolean.valueOf(enabled).toString().toUpperCase()); + return map; + } + + public void enable() { + fireSourceChanged(ISources.WORKBENCH, CONFIGURED_STATE, "TRUE"); //$NON-NLS-1$ + } + + public void disable() { + fireSourceChanged(ISources.WORKBENCH, CONFIGURED_STATE, "FALSE"); //$NON-NLS-1$ + } + + @Override + public void dispose() { + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/PropertyTester.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/PropertyTester.java new file mode 100644 index 00000000000..021a7cfd5d1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/PropertyTester.java @@ -0,0 +1,60 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal; + +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; + + +/** + * Terminal property tester implementation. + */ +public class PropertyTester extends org.eclipse.core.expressions.PropertyTester { + + /* (non-Javadoc) + * @see org.eclipse.core.expressions.IPropertyTester#test(java.lang.Object, java.lang.String, java.lang.Object[], java.lang.Object) + */ + @SuppressWarnings("cast") + @Override + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + + if ("hasApplicableLauncherDelegates".equals(property)) { //$NON-NLS-1$ + ISelection selection = receiver instanceof ISelection ? (ISelection)receiver : new StructuredSelection(receiver); + return expectedValue.equals(Boolean.valueOf(LauncherDelegateManager.getInstance().getApplicableLauncherDelegates(selection).length > 0)); + } + + if ("canDisconnect".equals(property) && receiver instanceof ITerminalsView) { //$NON-NLS-1$ + CTabItem tabItem = null; + + TabFolderManager manager = (TabFolderManager) ((ITerminalsView)receiver).getAdapter(TabFolderManager.class); + if (manager != null) { + tabItem = manager.getActiveTabItem(); + } + + if (tabItem != null && !tabItem.isDisposed() && tabItem.getData() instanceof ITerminalViewControl) { + ITerminalViewControl terminal = (ITerminalViewControl)tabItem.getData(); + TerminalState state = terminal.getState(); + return expectedValue.equals(Boolean.valueOf(state != TerminalState.CLOSED)); + } + return false; + } + + return false; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/SettingsStore.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/SettingsStore.java new file mode 100644 index 00000000000..719a24201a6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/SettingsStore.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; + +/** + * Simple default Terminal settings store implementation keeping the settings + * within memory. + */ +public class SettingsStore implements ISettingsStore { + private final Map settings = new HashMap(); + + /** + * Constructor. + */ + public SettingsStore() { + } + + /** + * Returns the map containing the settings. + * + * @return The map containing the settings. + */ + public final Map getSettings() { + return settings; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String, java.lang.String) + */ + @Override + public final String get(String key, String defaultValue) { + Assert.isNotNull(key); + String value = settings.get(key) instanceof String ? (String) settings.get(key) : null; + return value != null ? value : defaultValue; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String) + */ + @Override + public final String get(String key) { + Assert.isNotNull(key); + return settings.get(key) instanceof String ? (String) settings.get(key) : null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#put(java.lang.String, java.lang.String) + */ + @Override + public final void put(String key, String value) { + Assert.isNotNull(key); + if (value == null) settings.remove(key); + else settings.put(key, value); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java new file mode 100644 index 00000000000..72c4d8c414f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/EncodingSelectionDialog.java @@ -0,0 +1,232 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.dialogs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.terminal.view.ui.help.IContextHelpIds; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.tm.terminal.view.ui.panels.AbstractExtendedConfigurationPanel; +import org.eclipse.ui.PlatformUI; + +/** + * Encoding selection dialog implementation. + */ +public class EncodingSelectionDialog extends TrayDialog { + private String contextHelpId = null; + + // The selected encoding or null + /* default */ String encoding = null; + + // Reference to the encodings panel + private EncodingPanel encodingPanel = null; + + /** + * Encodings panel implementation + */ + protected class EncodingPanel extends AbstractExtendedConfigurationPanel { + + /** + * Constructor + * + * @param container The configuration panel container or null. + */ + public EncodingPanel(IConfigurationPanelContainer container) { + super(container); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupPanel(org.eclipse.swt.widgets.Composite) + */ + @Override + public void setupPanel(Composite parent) { + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + GridData data = new GridData(SWT.FILL, SWT.FILL, true, true); + panel.setLayoutData(data); + + // Create the encoding selection combo + createEncodingUI(panel, false); + if (EncodingSelectionDialog.this.encoding != null) { + setEncoding(EncodingSelectionDialog.this.encoding); + } + + setControl(panel); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#saveSettingsForHost(boolean) + */ + @Override + protected void saveSettingsForHost(boolean add) { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#fillSettingsForHost(java.lang.String) + */ + @Override + protected void fillSettingsForHost(String host) { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#getHostFromSettings() + */ + @Override + protected String getHostFromSettings() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#getEncoding() + */ + @Override + public String getEncoding() { + return super.getEncoding(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#setEncoding(java.lang.String) + */ + @Override + public void setEncoding(String encoding) { + super.setEncoding(encoding); + } + } + + /** + * Constructor. + * + * @param shell The parent shell or null. + */ + public EncodingSelectionDialog(Shell shell) { + super(shell); + + this.contextHelpId = IContextHelpIds.ENCODING_SELECTION_DIALOG; + setHelpAvailable(true); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected final Control createDialogArea(Composite parent) { + if (contextHelpId != null) { + PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, contextHelpId); + } + + // Let the super implementation create the dialog area control + Control control = super.createDialogArea(parent); + // Setup the inner panel as scrollable composite + if (control instanceof Composite) { + ScrolledComposite sc = new ScrolledComposite((Composite)control, SWT.V_SCROLL); + + GridLayout layout = new GridLayout(1, true); + layout.marginHeight = 0; layout.marginWidth = 0; + layout.verticalSpacing = 0; layout.horizontalSpacing = 0; + + sc.setLayout(layout); + sc.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); + + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + Composite composite = new Composite(sc, SWT.NONE); + composite.setLayout(new GridLayout()); + + // Setup the dialog area content + createDialogAreaContent(composite); + + sc.setContent(composite); + sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + // Return the scrolled composite as new dialog area control + control = sc; + } + + return control; + } + + /** + * Creates the dialog area content. + * + * @param parent The parent composite. Must not be null. + */ + protected void createDialogAreaContent(Composite parent) { + Assert.isNotNull(parent); + + setDialogTitle(Messages.EncodingSelectionDialog_title); + + Composite panel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); + + encodingPanel = new EncodingPanel(null); + encodingPanel.setupPanel(panel); + + applyDialogFont(panel); + } + + /** + * Sets the title for this dialog. + * + * @param title The title. + */ + public void setDialogTitle(String title) { + if (getShell() != null && !getShell().isDisposed()) { + getShell().setText(title); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#okPressed() + */ + @Override + protected void okPressed() { + // Save the selected encoding + if (encodingPanel != null) encoding = encodingPanel.getEncoding(); + super.okPressed(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#cancelPressed() + */ + @Override + protected void cancelPressed() { + // Reset the encoding + encoding = null; + super.cancelPressed(); + } + + /** + * Set the encoding to default to on creating the dialog. + */ + public final void setEncoding(String encoding) { + this.encoding = encoding; + } + + /** + * Returns the selected encoding or null. + */ + public final String getEncoding() { + return encoding; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/LaunchTerminalSettingsDialog.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/LaunchTerminalSettingsDialog.java new file mode 100644 index 00000000000..945f6c37b59 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/dialogs/LaunchTerminalSettingsDialog.java @@ -0,0 +1,649 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361352] [TERMINALS][SSH] Add SSH terminal support + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.dialogs; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +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.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.MessageBox; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.controls.ConfigurationPanelControl; +import org.eclipse.tm.terminal.view.ui.help.IContextHelpIds; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IExternalExecutablesProperties; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.interfaces.tracing.ITraceIds; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.tm.terminal.view.ui.local.showin.ExternalExecutablesManager; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.ISelectionService; +import org.eclipse.ui.PlatformUI; + +/** + * Launch terminal settings dialog implementation. + */ +public class LaunchTerminalSettingsDialog extends TrayDialog { + private String contextHelpId = null; + + // The parent selection + private ISelection selection = null; + + // The sub controls + /* default */ Combo terminals; + /* default */ SettingsPanelControl settings; + + // Map the label added to the combo box to the corresponding launcher delegate. + /* default */ final Map label2delegate = new HashMap(); + + // Map the label added to the combo box to the corresponding launcher properties for external executables. + /* default */ final Map> label2properties = new HashMap>(); + + // The data object containing the currently selected settings + private Map data = null; + + // The dialog settings storage + private IDialogSettings dialogSettings; + + // In case of a single available terminal launcher delegate, the label of that delegate + private String singleDelegateLabel = null; + + /** + * The control managing the terminal setting panels. + */ + protected class SettingsPanelControl extends ConfigurationPanelControl { + + /** + * Constructor. + */ + public SettingsPanelControl() { + setPanelIsGroup(true); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.controls.ConfigurationPanelControl#getGroupLabel() + */ + @Override + public String getGroupLabel() { + return Messages.LaunchTerminalSettingsDialog_group_label; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.controls.ConfigurationPanelControl#showConfigurationPanel(java.lang.String) + */ + @Override + public void showConfigurationPanel(String key) { + // Check if we have to create the panel first + IConfigurationPanel configPanel = getConfigurationPanel(key); + if (isEmptyConfigurationPanel(configPanel)) { + // Get the corresponding delegate + ILauncherDelegate delegate = label2delegate.get(key); + Assert.isNotNull(delegate); + // Create the wizard configuration panel instance + configPanel = delegate.getPanel(this); + if (configPanel != null) { + // Add it to the settings panel control + settings.addConfigurationPanel(key, configPanel); + // Push the selection to the configuration panel + configPanel.setSelection(getSelection()); + // Create the panel controls + configPanel.setupPanel(getPanel()); + // Restore widget values + IDialogSettings dialogSettings = LaunchTerminalSettingsDialog.this.settings.getDialogSettings(LaunchTerminalSettingsDialog.this.getDialogSettings()); + IDialogSettings configPanelSettings = dialogSettings != null ? dialogSettings.getSection(key) : null; + if (configPanelSettings != null) configPanel.doRestoreWidgetValues(configPanelSettings, null); + } + } + + super.showConfigurationPanel(key); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer#validate() + */ + @Override + public void validate() { + LaunchTerminalSettingsDialog.this.validate(); + } + } + + /** + * Constructor. + * + * @param shell The parent shell or null. + */ + public LaunchTerminalSettingsDialog(Shell shell) { + this(shell, 0); + } + + private long start = 0; + + /** + * Constructor. + * + * @param shell The parent shell or null. + */ + public LaunchTerminalSettingsDialog(Shell shell, long start) { + super(shell); + this.start = start; + + initializeDialogSettings(); + + this.contextHelpId = IContextHelpIds.LAUNCH_TERMINAL_SETTINGS_DIALOG; + setHelpAvailable(true); + } + + /** + * Sets the parent selection. + * + * @param selection The parent selection or null. + */ + public void setSelection(ISelection selection) { + this.selection = selection; + } + + /** + * Returns the parent selection. + * + * @return The parent selection or null. + */ + public ISelection getSelection() { + return selection; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#close() + */ + @Override + public boolean close() { + dispose(); + return super.close(); + } + + /** + * Dispose the dialog resources. + */ + protected void dispose() { + if (settings != null) { settings.dispose(); settings = null; } + dialogSettings = null; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#isResizable() + */ + @Override + protected boolean isResizable() { + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createContents(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createContents(Composite parent) { + Control composite = super.createContents(parent); + + // Validate the dialog after having created all the content + validate(); + + return composite; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected final Control createDialogArea(Composite parent) { + if (contextHelpId != null) { + PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, contextHelpId); + } + + // Let the super implementation create the dialog area control + Control control = super.createDialogArea(parent); + // Setup the inner panel as scrollable composite + if (control instanceof Composite) { + ScrolledComposite sc = new ScrolledComposite((Composite)control, SWT.V_SCROLL); + + GridLayout layout = new GridLayout(1, true); + layout.marginHeight = 0; layout.marginWidth = 0; + layout.verticalSpacing = 0; layout.horizontalSpacing = 0; + + sc.setLayout(layout); + sc.setLayoutData(new GridData(GridData.FILL_BOTH | GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL)); + + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + Composite composite = new Composite(sc, SWT.NONE); + composite.setLayout(new GridLayout()); + + // Setup the dialog area content + createDialogAreaContent(composite); + + sc.setContent(composite); + sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + // Return the scrolled composite as new dialog area control + control = sc; + } + + return control; + } + + /** + * Sets the title for this dialog. + * + * @param title The title. + */ + public void setDialogTitle(String title) { + if (getShell() != null && !getShell().isDisposed()) { + getShell().setText(title); + } + } + + /** + * Creates the dialog area content. + * + * @param parent The parent composite. Must not be null. + */ + protected void createDialogAreaContent(Composite parent) { + Assert.isNotNull(parent); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Creating dialog area after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + + setDialogTitle(Messages.LaunchTerminalSettingsDialog_title); + + final List items = getTerminals(); + + Composite panel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); + + if (items.size() != 1) { + Label label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.LaunchTerminalSettingsDialog_combo_label); + + terminals = new Combo(panel, SWT.READ_ONLY); + terminals.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + terminals.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + // Get the old panel + IConfigurationPanel oldPanel = settings.getActiveConfigurationPanel(); + // Extract the current settings in an special properties container + Map data = new HashMap(); + if (oldPanel != null) oldPanel.extractData(data); + // Clean out settings which are never passed between the panels + data.remove(ITerminalsConnectorConstants.PROP_IP_PORT); + data.remove(ITerminalsConnectorConstants.PROP_TIMEOUT); + data.remove(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + data.remove(ITerminalsConnectorConstants.PROP_ENCODING); + // Switch to the new panel + settings.showConfigurationPanel(terminals.getText()); + // Get the new panel + IConfigurationPanel newPanel = settings.getActiveConfigurationPanel(); + // Re-setup the relevant data + if (newPanel != null) newPanel.setupData(data); + + // resize the dialog if needed to show the complete panel + getShell().pack(); + // validate the settings dialog + validate(); + } + }); + + // fill the combo with content + fillCombo(terminals, items); + } else { + Assert.isTrue(items.size() == 1); + singleDelegateLabel = items.get(0); + } + + // Create the settings panel control + settings = new SettingsPanelControl(); + + // Create, initialize and add the first visible panel. All + // other panels are created on demand only. + String terminalLabel = terminals != null ? terminals.getItem(0) : singleDelegateLabel; + if (terminalLabel != null) { + // Get the corresponding delegate + ILauncherDelegate delegate = label2delegate.get(terminalLabel); + Assert.isNotNull(delegate); + // Create the wizard configuration panel instance + IConfigurationPanel configPanel = delegate.getPanel(settings); + if (configPanel != null) { + // Add it to the settings panel control + settings.addConfigurationPanel(terminalLabel, configPanel); + // Push the selection to the configuration panel + configPanel.setSelection(getSelection()); + } + } + + // Setup the panel control + settings.setupPanel(panel, terminals != null ? terminals.getItems() : new String[] { singleDelegateLabel }); + GridData layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.horizontalSpan = 2; + settings.getPanel().setLayoutData(layoutData); + + // Preselect the first terminal launcher + if (terminals != null) { + terminals.select(0); + settings.showConfigurationPanel(terminals.getText()); + + terminals.setEnabled(terminals.getItemCount() > 1); + } else { + settings.showConfigurationPanel(singleDelegateLabel); + } + + restoreWidgetValues(); + + applyDialogFont(panel); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Created dialog area after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + } + + /** + * Fill the given combo with the given list of terminal launcher delegate labels. + * + * @param combo The combo. Must not be null. + * @param items The list of terminal launcher delegates. Must not be null. + */ + protected void fillCombo(Combo combo, List items) { + Assert.isNotNull(combo); + Assert.isNotNull(items); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Filling combo after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + + Collections.sort(items); + combo.setItems(items.toArray(new String[items.size()])); + } + + /** + * Returns the list of terminal launcher delegate labels. The method queries the + * terminal launcher delegates and initialize the label2delegate map. + * + * @return The list of terminal launcher delegate labels or an empty list. + */ + protected List getTerminals() { + List items = new ArrayList(); + + ILauncherDelegate localLauncher = null; + + if(selection==null || selection.isEmpty()){ + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Getting launcher delegates after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + + ILauncherDelegate[] delegates = LauncherDelegateManager.getInstance().getLauncherDelegates(false); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Got launcher delegates after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + + for (ILauncherDelegate delegate : delegates) { + if (delegate.isHidden() || isFiltered(selection, delegate)) continue; + String label = delegate.getLabel(); + if (label == null || "".equals(label.trim()) || label2delegate.containsKey(label)) label = delegate.getId(); //$NON-NLS-1$ + label2delegate.put(label, delegate); + items.add(label); + + if ("org.eclipse.tm.terminal.connector.local.launcher.local".equals(delegate.getId())) { //$NON-NLS-1$ + localLauncher = delegate; + } + } + } else { + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Getting applicable launcher delegates after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + + ILauncherDelegate[] delegates = LauncherDelegateManager.getInstance().getApplicableLauncherDelegates(selection); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Got applicable launcher delegates after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalSettingsDialog.this); + } + + for (ILauncherDelegate delegate : delegates) { + if (delegate.isHidden() || isFiltered(selection, delegate)) continue; + String label = delegate.getLabel(); + if (label == null || "".equals(label.trim())) label = delegate.getId(); //$NON-NLS-1$ + label2delegate.put(label, delegate); + items.add(label); + + if ("org.eclipse.tm.terminal.connector.local.launcher.local".equals(delegate.getId())) { //$NON-NLS-1$ + localLauncher = delegate; + } + } + } + + // if the local launcher was found, check for configured external executables + if (localLauncher != null) { + List> l = ExternalExecutablesManager.load(); + if (l != null && !l.isEmpty()) { + for (Map executableData : l) { + String name = executableData.get(IExternalExecutablesProperties.PROP_NAME); + String path = executableData.get(IExternalExecutablesProperties.PROP_PATH); + String args = executableData.get(IExternalExecutablesProperties.PROP_ARGS); + + String strTranslate = executableData.get(IExternalExecutablesProperties.PROP_TRANSLATE); + boolean translate = strTranslate != null ? Boolean.parseBoolean(strTranslate) : false; + + if (name != null && !"".equals(name) && path != null && !"".equals(path)) { //$NON-NLS-1$ //$NON-NLS-2$ + ISelectionService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); + ISelection selection = service != null ? service.getSelection() : null; + if (selection != null && selection.isEmpty()) selection = null; + + Map properties = new HashMap(); + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_PATH, path); + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, args); + properties.put(ITerminalsConnectorConstants.PROP_TRANSLATE_BACKSLASHES_ON_PASTE, Boolean.valueOf(translate)); + + // store external executable and properties + label2delegate.put(name, localLauncher); + label2properties.put(name, properties); + items.add(name); + } + } + } + + } + + return items; + } + + /** + * Hook to allow additional filtering of the applicable launcher delegates. + *

            + * Note: The default implementation always returns false. + * + * @param selection The selection or null. + * @param delegate The launcher delegate. Must not be null. + * + * @return True if the launcher delegate is filtered based on the given selection, false otherwise. + */ + protected boolean isFiltered(ISelection selection, ILauncherDelegate delegate) { + return false; + } + + /** + * Validate the dialog. + */ + public void validate() { + IConfigurationPanel panel = this.settings.getActiveConfigurationPanel(); + Button okButton = getButton(IDialogConstants.OK_ID); + if (okButton != null) okButton.setEnabled(panel.isValid()); + } + + /** + * Set the given message and message type. + * + * @param message The message or null. + * @param messageType The message type or IMessageProvider.NONE. + */ + public void setMessage(String message, int messageType) { + if (settings != null) { + settings.setMessage(message, messageType); + } + } + + /** + * Save the dialog's widget values. + */ + protected void saveWidgetValues() { + IDialogSettings settings = getDialogSettings(); + if (settings != null && terminals != null) { + settings.put("terminalLabel", terminals.getText()); //$NON-NLS-1$ + this.settings.saveWidgetValues(settings, null); + } + } + + /** + * Restore the dialog's widget values. + */ + protected void restoreWidgetValues() { + IDialogSettings settings = getDialogSettings(); + if (settings != null) { + String terminalLabel = settings.get("terminalLabel"); //$NON-NLS-1$ + int index = terminalLabel != null && terminals != null ? Arrays.asList(terminals.getItems()).indexOf(terminalLabel) : -1; + if (index != -1) { + terminals.select(index); + this.settings.showConfigurationPanel(terminals.getText()); + } + + this.settings.restoreWidgetValues(settings, null); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#okPressed() + */ + @Override + protected void okPressed() { + IConfigurationPanel panel = this.settings.getActiveConfigurationPanel(); + Assert.isNotNull(panel); + + if (!panel.isValid()) { + MessageBox mb = new MessageBox(getShell(), SWT.ICON_ERROR | SWT.OK); + mb.setText(Messages.LaunchTerminalSettingsDialog_error_title); + mb.setMessage(NLS.bind(Messages.LaunchTerminalSettingsDialog_error_invalidSettings, panel.getMessage() != null ? panel.getMessage() : Messages.LaunchTerminalSettingsDialog_error_unknownReason)); + mb.open(); + return; + } + data = new HashMap(); + + // Store the id of the selected delegate + String terminalLabel = terminals != null ? terminals.getText() : singleDelegateLabel; + String delegateId = terminalLabel != null ? label2delegate.get(terminalLabel).getId() : null; + if (delegateId != null) data.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, delegateId); + // Store the selection + data.put(ITerminalsConnectorConstants.PROP_SELECTION, selection); + + // Add the properties for external executables if there are any + if (label2properties.containsKey(terminalLabel)) { + data.putAll(label2properties.get(terminalLabel)); + } + + // Store the delegate specific settings + panel.extractData(data); + + // Save the current widget values + saveWidgetValues(); + + super.okPressed(); + } + + /** + * Returns the configured terminal launcher settings. + *

            + * The settings are extracted from the UI widgets once + * OK got pressed. + * + * @return The configured terminal launcher settings or null. + */ + public Map getSettings() { + return data; + } + + /** + * Initialize the dialog settings storage. + */ + protected void initializeDialogSettings() { + IDialogSettings settings = UIPlugin.getDefault().getDialogSettings(); + Assert.isNotNull(settings); + IDialogSettings section = settings.getSection(getClass().getSimpleName()); + if (section == null) { + section = settings.addNewSection(getClass().getSimpleName()); + } + setDialogSettings(section); + } + + /** + * Returns the associated dialog settings storage. + * + * @return The dialog settings storage. + */ + public IDialogSettings getDialogSettings() { + // The dialog settings may not been initialized here. Initialize first in this case + // to be sure that we do have always the correct dialog settings. + if (dialogSettings == null) { + initializeDialogSettings(); + } + return dialogSettings; + } + + /** + * Sets the associated dialog settings storage. + * + * @return The dialog settings storage. + */ + public void setDialogSettings(IDialogSettings dialogSettings) { + this.dialogSettings = dialogSettings; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/AbstractTriggerCommandHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/AbstractTriggerCommandHandler.java new file mode 100644 index 00000000000..cbe783db89f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/AbstractTriggerCommandHandler.java @@ -0,0 +1,70 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.handler; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.ISources; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; + +/** + * Abstract command handler triggering a command to be executed. + */ +public abstract class AbstractTriggerCommandHandler extends AbstractHandler { + + /** + * Trigger a command to be executed. + * + * @param commandId The command id. Must not be null. + * @param selection The selection to pass on to the command or null. + */ + @SuppressWarnings("cast") + protected void triggerCommand(String commandId, ISelection selection) { + Assert.isNotNull(commandId); + + ICommandService service = (ICommandService)PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = service != null ? service.getCommand(commandId) : null; + if (command != null && command.isDefined() && command.isEnabled()) { + try { + ParameterizedCommand pCmd = ParameterizedCommand.generateCommand(command, null); + Assert.isNotNull(pCmd); + IHandlerService handlerSvc = (IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class); + Assert.isNotNull(handlerSvc); + IEvaluationContext ctx = handlerSvc.getCurrentState(); + if (selection != null) { + ctx = new EvaluationContext(ctx, selection); + ctx.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection); + } + handlerSvc.executeCommandInContext(pCmd, null, ctx); + } catch (Exception e) { + // If the platform is in debug mode, we print the exception to the log view + if (Platform.inDebugMode()) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + Messages.AbstractTriggerCommandHandler_error_executionFailed, e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/DisconnectTerminalCommandHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/DisconnectTerminalCommandHandler.java new file mode 100644 index 00000000000..30304d2baa7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/DisconnectTerminalCommandHandler.java @@ -0,0 +1,64 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.handler; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Disconnect terminal connection command handler implementation. + */ +public class DisconnectTerminalCommandHandler extends AbstractHandler { + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @SuppressWarnings("cast") + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + CTabItem item = null; + + ISelection selection = HandlerUtil.getCurrentSelection(event); + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + Object element = ((IStructuredSelection)selection).getFirstElement(); + if (element instanceof CTabItem && ((CTabItem)element).getData() instanceof ITerminalViewControl) { + item = (CTabItem)element; + } + } + + if (item == null && HandlerUtil.getActivePart(event) instanceof ITerminalsView) { + ITerminalsView view = (ITerminalsView)HandlerUtil.getActivePart(event); + TabFolderManager mgr = (TabFolderManager)view.getAdapter(TabFolderManager.class); + if (mgr != null && mgr.getActiveTabItem() != null) { + item = mgr.getActiveTabItem(); + } + } + + if (item != null && item.getData() instanceof ITerminalViewControl) { + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal != null && !terminal.isDisposed()) { + terminal.disconnectTerminal(); + } + } + + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/LaunchTerminalCommandHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/LaunchTerminalCommandHandler.java new file mode 100644 index 00000000000..6679811c9ad --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/LaunchTerminalCommandHandler.java @@ -0,0 +1,159 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.handler; + +import java.text.DateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.tm.terminal.view.core.TerminalContextPropertiesProviderFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalContextPropertiesProvider; +import org.eclipse.tm.terminal.view.core.interfaces.constants.IContextPropertiesConstants; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.interfaces.tracing.ITraceIds; +import org.eclipse.tm.terminal.view.ui.internal.dialogs.LaunchTerminalSettingsDialog; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.ui.handlers.HandlerUtil; + +/** + * Launch terminal command handler implementation. + */ +public class LaunchTerminalCommandHandler extends AbstractHandler { + + /* + * (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + String commandId = event.getCommand().getId(); + // "org.eclipse.tm.terminal.view.ui.command.launchToolbar" + // "org.eclipse.tm.terminal.view.ui.command.launch" + + long start = System.currentTimeMillis(); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + DateFormat format = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT); + String date = format.format(new Date(start)); + + UIPlugin.getTraceHandler().trace("Started at " + date + " (" + start + ")", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalCommandHandler.this); + } + + // Get the active shell + Shell shell = HandlerUtil.getActiveShell(event); + // Get the current selection + ISelection selection = HandlerUtil.getCurrentSelection(event); + + if (commandId.equals("org.eclipse.tm.terminal.view.ui.command.launchToolbar")) { //$NON-NLS-1$ + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("(a) Attempt to open launch terminal settings dialog after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalCommandHandler.this); + } + + LaunchTerminalSettingsDialog dialog = new LaunchTerminalSettingsDialog(shell, start); + + if(isValidSelection(selection)){ + dialog.setSelection(selection); + } + if (dialog.open() == Window.OK) { + // Get the terminal settings from the dialog + Map properties = dialog.getSettings(); + if (properties != null) { + String delegateId = (String)properties.get(ITerminalsConnectorConstants.PROP_DELEGATE_ID); + Assert.isNotNull(delegateId); + ILauncherDelegate delegate = LauncherDelegateManager.getInstance().getLauncherDelegate(delegateId, false); + Assert.isNotNull(delegateId); + delegate.execute(properties, null); + } + } + } + else { + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Getting applicable launcher delegates after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalCommandHandler.this); + } + + // Check if the dialog needs to be shown at all + ILauncherDelegate[] delegates = LauncherDelegateManager.getInstance().getApplicableLauncherDelegates(selection); + + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("Got applicable launcher delegates after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalCommandHandler.this); + } + + if (delegates.length > 1 || (delegates.length == 1 && delegates[0].needsUserConfiguration())) { + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER)) { + UIPlugin.getTraceHandler().trace("(b) Attempt to open launch terminal settings dialog after " + (System.currentTimeMillis() - start) + " ms.", //$NON-NLS-1$ //$NON-NLS-2$ + ITraceIds.TRACE_LAUNCH_TERMINAL_COMMAND_HANDLER, LaunchTerminalCommandHandler.this); + } + + // Create the launch terminal settings dialog + LaunchTerminalSettingsDialog dialog = new LaunchTerminalSettingsDialog(shell, start); + if(isValidSelection(selection)){ + dialog.setSelection(selection); + } + if (dialog.open() == Window.OK) { + // Get the terminal settings from the dialog + Map properties = dialog.getSettings(); + if (properties != null) { + String delegateId = (String)properties.get(ITerminalsConnectorConstants.PROP_DELEGATE_ID); + Assert.isNotNull(delegateId); + ILauncherDelegate delegate = LauncherDelegateManager.getInstance().getLauncherDelegate(delegateId, false); + Assert.isNotNull(delegateId); + delegate.execute(properties, null); + } + } + } + else if (delegates.length == 1) { + ILauncherDelegate delegate = delegates[0]; + Map properties = new HashMap(); + + // Store the id of the selected delegate + properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, delegate.getId()); + // Store the selection + properties.put(ITerminalsConnectorConstants.PROP_SELECTION, selection); + + // Execute + delegate.execute(properties, null); + } + } + + return null; + } + + private boolean isValidSelection(ISelection selection) { + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + ITerminalContextPropertiesProvider provider = TerminalContextPropertiesProviderFactory.getProvider(element); + if (provider != null) { + Map props = provider.getTargetAddress(element); + if (props != null && props.containsKey(IContextPropertiesConstants.PROP_ADDRESS)) { + return true; + } + } + } + + return false; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/MaximizeViewHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/MaximizeViewHandler.java new file mode 100644 index 00000000000..ec54a1a185a --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/MaximizeViewHandler.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.handler; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +/** + * Maximize view handler implementation. + */ +public class MaximizeViewHandler extends AbstractTriggerCommandHandler { + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + triggerCommand("org.eclipse.ui.window.maximizePart", null); //$NON-NLS-1$ + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/NewTerminalViewHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/NewTerminalViewHandler.java new file mode 100644 index 00000000000..08655f1697f --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/NewTerminalViewHandler.java @@ -0,0 +1,37 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.handler; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.tm.terminal.view.ui.interfaces.IUIConstants; +import org.eclipse.tm.terminal.view.ui.manager.ConsoleManager; + +/** + * New Terminal View handler implementation + */ +public class NewTerminalViewHandler extends AbstractTriggerCommandHandler { + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + String secondaryId = ConsoleManager.getInstance().getNextTerminalSecondaryId(IUIConstants.ID); + ConsoleManager.getInstance().showConsoleView(IUIConstants.ID, secondaryId); + + triggerCommand("org.eclipse.tm.terminal.view.ui.command.launchToolbar", null); //$NON-NLS-1$ + + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/QuickAccessHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/QuickAccessHandler.java new file mode 100644 index 00000000000..b7a1d45dc78 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/internal/handler/QuickAccessHandler.java @@ -0,0 +1,31 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.internal.handler; + +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; + +/** + * Quick access handler implementation. + */ +public class QuickAccessHandler extends AbstractTriggerCommandHandler { + + /* (non-Javadoc) + * @see org.eclipse.core.commands.IHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + @Override + public Object execute(ExecutionEvent event) throws ExecutionException { + triggerCommand("org.eclipse.ui.window.quickAccess", null); //$NON-NLS-1$ + return null; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/launcher/AbstractLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/launcher/AbstractLauncherDelegate.java new file mode 100644 index 00000000000..ac97ae5e80c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/launcher/AbstractLauncherDelegate.java @@ -0,0 +1,161 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.launcher; + +import java.util.Map; + +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.ExpressionConverter; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.nls.Messages; + +/** + * Abstract launcher delegate implementation. + */ +public abstract class AbstractLauncherDelegate extends PlatformObject implements ILauncherDelegate { + // The mandatory id of the extension + private String id = null; + // The label of the extension + private String label = null; + // The converted expression + private Expression expression; + // The hidden attribute + private boolean hidden; + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IExecutableExtension#setInitializationData(org.eclipse.core.runtime.IConfigurationElement, java.lang.String, java.lang.Object) + */ + @Override + public void setInitializationData(IConfigurationElement config, String propertyName, Object data) throws CoreException { + if (config == null) return; + + // Initialize the id field by reading the extension attribute. + // Throws an exception if the id is empty or null. + id = config.getAttribute("id"); //$NON-NLS-1$ + if (id == null || "".equals(id.trim())) { //$NON-NLS-1$ + throw createMissingMandatoryAttributeException("id", config.getContributor().getName()); //$NON-NLS-1$ + } + + // Try the "label" attribute first + label = config.getAttribute("label"); //$NON-NLS-1$ + // If "label" is not found or empty, try the "name" attribute as fallback + if (label == null || "".equals(label.trim())) { //$NON-NLS-1$ + label = config.getAttribute("name"); //$NON-NLS-1$ + } + + // Read the sub elements of the extension + IConfigurationElement[] children = config.getChildren(); + // The "enablement" element is the only expected one + if (children != null && children.length > 0) { + expression = ExpressionConverter.getDefault().perform(children[0]); + } + + // Read "hidden" attribute + String value = config.getAttribute("hidden"); //$NON-NLS-1$ + if (value != null && !"".equals(value.trim())) { //$NON-NLS-1$ + hidden = Boolean.parseBoolean(value); + } + } + + /** + * Creates a new {@link CoreException} to be thrown if a mandatory extension attribute + * is missing. + * + * @param attributeName The attribute name. Must not be null. + * @param extensionId The extension id. Must not be null. + * + * @return The {@link CoreException} instance. + */ + protected CoreException createMissingMandatoryAttributeException(String attributeName, String extensionId) { + Assert.isNotNull(attributeName); + Assert.isNotNull(extensionId); + + return new CoreException(new Status(IStatus.ERROR, + UIPlugin.getUniqueIdentifier(), + 0, + NLS.bind(Messages.Extension_error_missingRequiredAttribute, attributeName, extensionId), + null)); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getId() + */ + @Override + public String getId() { + return id; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getLabel() + */ + @Override + public String getLabel() { + return label != null ? label.trim() : ""; //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getEnablement() + */ + @Override + public Expression getEnablement() { + return expression; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#isHidden() + */ + @Override + public boolean isHidden() { + return hidden; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof AbstractLauncherDelegate) { + return id.equals(((AbstractLauncherDelegate)obj).id); + } + return super.equals(obj); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + return id.hashCode(); + } + + /** + * Get the title from the settings, and use it as the default title. + * + * @param properties the setting properties map. + * @return the value retrieved via the @see {@link ITerminalsConnectorConstants#PROP_TITLE}, or null if the key hasn't been set. + * + * @since 4.1 + */ + protected String getDefaultTerminalTitle(Map properties) { + String title = (String)properties.get(ITerminalsConnectorConstants.PROP_TITLE); + return title != null ? title : null; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/launcher/LauncherDelegateManager.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/launcher/LauncherDelegateManager.java new file mode 100644 index 00000000000..9f30fb98fe6 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/launcher/LauncherDelegateManager.java @@ -0,0 +1,424 @@ +/******************************************************************************* + * Copyright (c) 2011 - 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.launcher; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.EvaluationResult; +import org.eclipse.core.expressions.Expression; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IConfigurationElement; +import org.eclipse.core.runtime.IExtension; +import org.eclipse.core.runtime.IExtensionPoint; +import org.eclipse.core.runtime.IExtensionRegistry; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.ISources; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.handlers.IHandlerService; + +/** + * Terminal launcher delegate manager implementation. + */ +public class LauncherDelegateManager { + // Flag to mark the extension point manager initialized (extensions loaded). + private boolean initialized = false; + + // The map containing all loaded contributions + private final Map extensionsMap = new HashMap(); + + // The extension point comparator + private ExtensionPointComparator comparator = null; + + /** + * Executable extension proxy implementation. + */ + /* default */ static class Proxy { + // The extension instance. Created on first access + private ILauncherDelegate instance; + // The configuration element + private final IConfigurationElement element; + // The unique id of the extension. + private String id; + + /** + * Constructor. + * + * @param element The configuration element. Must not be null. + * @throws CoreException In case the configuration element attribute id is null or empty. + */ + public Proxy(IConfigurationElement element) throws CoreException { + Assert.isNotNull(element); + this.element = element; + + // Extract the extension attributes + id = element.getAttribute("id"); //$NON-NLS-1$ + if (id == null || id.trim().length() == 0) { + throw new CoreException(new Status(IStatus.ERROR, + UIPlugin.getUniqueIdentifier(), + 0, + NLS.bind(Messages.Extension_error_missingRequiredAttribute, "id", element.getContributor().getName()), //$NON-NLS-1$ + null)); + } + + instance = null; + } + + /** + * Returns the extensions unique id. + * + * @return The unique id. + */ + public String getId() { + return id; + } + + /** + * Returns the configuration element for this extension. + * + * @return The configuration element. + */ + public IConfigurationElement getConfigurationElement() { + return element; + } + + /** + * Returns the extension class instance. The contributing + * plug-in will be activated if not yet activated anyway. + * + * @return The extension class instance or null if the instantiation fails. + */ + public ILauncherDelegate getInstance() { + if (instance == null) instance = newInstance(); + return instance; + } + + /** + * Returns always a new extension class instance which is different + * to what {@link #getInstance()} would return. + * + * @return A new extension class instance or null if the instantiation fails. + */ + public ILauncherDelegate newInstance() { + IConfigurationElement element = getConfigurationElement(); + Assert.isNotNull(element); + + // The "class" to load can be specified either as attribute or as child element + if (element.getAttribute("class") != null || element.getChildren("class").length > 0) { //$NON-NLS-1$ //$NON-NLS-2$ + try { + return (ILauncherDelegate)element.createExecutableExtension("class"); //$NON-NLS-1$ + } catch (Exception e) { + // Possible exceptions: CoreException, ClassCastException. + Platform.getLog(UIPlugin.getDefault().getBundle()).log(new Status(IStatus.ERROR, + UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.Extension_error_invalidExtensionPoint, element.getDeclaringExtension().getUniqueIdentifier()), e)); + } + } + return null; + } + + /* (non-Javadoc) + * @see java.lang.Object#equals(java.lang.Object) + */ + @Override + public boolean equals(Object obj) { + // Proxies are equal if they have encapsulate an element + // with the same unique id + if (obj instanceof Proxy) { + return getId().equals(((Proxy)obj).getId()); + } + return super.equals(obj); + } + + /* (non-Javadoc) + * @see java.lang.Object#hashCode() + */ + @Override + public int hashCode() { + // The hash code of a proxy is the one from the id + return getId().hashCode(); + } + } + + /** + * Extension point comparator implementation. + *

            + * The comparator assure that extension are read in a predictable order. + *

            + * The order of the extensions is defined as following:
            + *

            • Extensions contributed by our own plug-ins (org.eclipse.tm.terminal.*) + * in ascending alphabetic order and
            • + *
            • Extensions contributed by any other plug-in in ascending alphabetic order.
            • + *
            • Extensions contributed by the same plug-in in ascending alphabetic order by the + * extensions unique id
            • + */ + /* default */ static class ExtensionPointComparator implements Comparator { + private final static String OWN_PLUGINS_PATTERN = "org.eclipse.tm.terminal."; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) + */ + @Override + public int compare(IExtension o1, IExtension o2) { + // We ignore any comparisation with null and + if (o1 == null || o2 == null) return 0; + // Check if it is the exact same element + if (o1 == o2) return 0; + + // The extensions are compared by the unique id of the contributing plug-in first + String contributor1 = o1.getContributor().getName(); + String contributor2 = o2.getContributor().getName(); + + // Contributions from our own plug-ins comes before 3rdParty plug-ins + if (contributor1.startsWith(OWN_PLUGINS_PATTERN) && !contributor2.startsWith(OWN_PLUGINS_PATTERN)) + return -1; + if (!contributor1.startsWith(OWN_PLUGINS_PATTERN) && contributor2.startsWith(OWN_PLUGINS_PATTERN)) + return 1; + if (contributor1.startsWith(OWN_PLUGINS_PATTERN) && contributor2.startsWith(OWN_PLUGINS_PATTERN)) { + int value = contributor1.compareTo(contributor2); + // Within the same plug-in, the extension are sorted by their unique id (if available) + if (value == 0 && o1.getUniqueIdentifier() != null && o2.getUniqueIdentifier() != null) + return o1.getUniqueIdentifier().compareTo(o2.getUniqueIdentifier()); + // Otherwise, just return the comparisation result from the contributors + return value; + } + + // Contributions from all other plug-ins are sorted alphabetical + int value = contributor1.compareTo(contributor2); + // Within the same plug-in, the extension are sorted by their unique id (if available) + if (value == 0 && o1.getUniqueIdentifier() != null && o2.getUniqueIdentifier() != null) + return o1.getUniqueIdentifier().compareTo(o2.getUniqueIdentifier()); + // Otherwise, just return the comparisation result from the contributors + return value; + } + + } + + /* + * Thread save singleton instance creation. + */ + private static class LazyInstanceHolder { + public static LauncherDelegateManager instance = new LauncherDelegateManager(); + } + + /** + * Returns the singleton instance. + */ + public static LauncherDelegateManager getInstance() { + return LazyInstanceHolder.instance; + } + + /** + * Constructor. + */ + LauncherDelegateManager() { + super(); + } + + /** + * Returns the list of all contributed terminal launcher delegates. + * + * @param unique If true, the method returns new instances for each + * contributed terminal launcher delegate. + * + * @return The list of contributed terminal launcher delegates, or an empty array. + */ + public ILauncherDelegate[] getLauncherDelegates(boolean unique) { + List contributions = new ArrayList(); + for (Proxy launcherDelegate : getExtensions().values()) { + ILauncherDelegate instance = unique ? launcherDelegate.newInstance() : launcherDelegate.getInstance(); + if (instance != null && !contributions.contains(instance)) { + contributions.add(instance); + } + } + + return contributions.toArray(new ILauncherDelegate[contributions.size()]); + } + + /** + * Returns the terminal launcher delegate identified by its unique id. If no terminal + * launcher delegate with the specified id is registered, null is returned. + * + * @param id The unique id of the terminal launcher delegate or null + * @param unique If true, the method returns new instances of the terminal launcher delegate contribution. + * + * @return The terminal launcher delegate instance or null. + */ + public ILauncherDelegate getLauncherDelegate(String id, boolean unique) { + ILauncherDelegate contribution = null; + Map extensions = getExtensions(); + if (extensions.containsKey(id)) { + Proxy proxy = extensions.get(id); + // Get the extension instance + contribution = unique ? proxy.newInstance() : proxy.getInstance(); + } + + return contribution; + } + + /** + * Returns the applicable terminal launcher delegates for the given selection. + * + * @param selection The selection or null. + * @return The list of applicable terminal launcher delegates or an empty array. + */ + @SuppressWarnings("cast") + public ILauncherDelegate[] getApplicableLauncherDelegates(ISelection selection) { + List applicable = new ArrayList(); + + for (ILauncherDelegate delegate : getLauncherDelegates(false)) { + Expression enablement = delegate.getEnablement(); + + // The launcher delegate is applicable by default if + // no expression is specified. + boolean isApplicable = enablement == null; + + if (enablement != null) { + if (selection != null) { + // Set the default variable to selection. + IEvaluationContext currentState = ((IHandlerService)PlatformUI.getWorkbench().getService(IHandlerService.class)).getCurrentState(); + EvaluationContext context = new EvaluationContext(currentState, selection); + // Set the "selection" variable to the selection. + context.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection); + // Allow plug-in activation + context.setAllowPluginActivation(true); + // Evaluate the expression + try { + isApplicable = enablement.evaluate(context).equals(EvaluationResult.TRUE); + } catch (CoreException e) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), e.getLocalizedMessage(), e); + UIPlugin.getDefault().getLog().log(status); + } + } else { + // The enablement is false by definition if + // there is no selection. + isApplicable = false; + } + } + + // Add the page if applicable + if (isApplicable) applicable.add(delegate); + } + + return applicable.toArray(new ILauncherDelegate[applicable.size()]); + } + + /** + * Returns the map of managed extensions. If not loaded before, + * this methods trigger the loading of the extensions to the managed + * extension point. + * + * @return The map of extensions. + */ + protected Map getExtensions() { + // Load and store the extensions thread-safe! + synchronized (extensionsMap) { + if (!initialized) { loadExtensions(); initialized = true; } + } + return extensionsMap; + } + + /** + * Returns the extension point comparator instance. If not available, + * {@link #doCreateExtensionPointComparator()} is called to create a new instance. + * + * @return The extension point comparator or null if the instance creation fails. + */ + protected final ExtensionPointComparator getExtensionPointComparator() { + if (comparator == null) { + comparator = new ExtensionPointComparator(); + } + return comparator; + } + + /** + * Returns the extensions of the specified extension point sorted. + *

              + * For the order of the extensions, see {@link ExtensionPointComparator}. + * + * @param point The extension point. Must not be null. + * @return The extensions in sorted order or an empty array if the extension point has no extensions. + */ + protected IExtension[] getExtensionsSorted(IExtensionPoint point) { + Assert.isNotNull(point); + + List extensions = new ArrayList(Arrays.asList(point.getExtensions())); + if (extensions.size() > 0) { + Collections.sort(extensions, getExtensionPointComparator()); + } + + return extensions.toArray(new IExtension[extensions.size()]); + } + + /** + * Loads the extensions for the managed extension point. + */ + protected void loadExtensions() { + // If already initialized, this method will do nothing. + if (initialized) return; + + IExtensionRegistry registry = Platform.getExtensionRegistry(); + IExtensionPoint point = registry.getExtensionPoint("org.eclipse.tm.terminal.view.ui.launcherDelegates"); //$NON-NLS-1$ + if (point != null) { + IExtension[] extensions = getExtensionsSorted(point); + for (IExtension extension : extensions) { + IConfigurationElement[] elements = extension.getConfigurationElements(); + for (IConfigurationElement element : elements) { + if ("delegate".equals(element.getName())) { //$NON-NLS-1$ + try { + Proxy candidate = new Proxy(element); + if (candidate.getId() != null) { + // If no extension with this id had been registered before, register now. + if (!extensionsMap.containsKey(candidate.getId())) { + extensionsMap.put(candidate.getId(), candidate); + } + else { + throw new CoreException(new Status(IStatus.ERROR, + UIPlugin.getUniqueIdentifier(), + 0, + NLS.bind(Messages.Extension_error_duplicateExtension, candidate.getId(), element.getContributor().getName()), + null)); + } + } else { + throw new CoreException(new Status(IStatus.ERROR, + UIPlugin.getUniqueIdentifier(), + 0, + NLS.bind(Messages.Extension_error_missingRequiredAttribute, "id", element.getAttribute("label")), //$NON-NLS-1$ //$NON-NLS-2$ + null)); + } + } catch (CoreException e) { + Platform.getLog(UIPlugin.getDefault().getBundle()).log(new Status(IStatus.ERROR, + UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.Extension_error_invalidExtensionPoint, element.getDeclaringExtension().getUniqueIdentifier()), e)); + } + } + } + } + } + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/AbstractWindowListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/AbstractWindowListener.java new file mode 100644 index 00000000000..df08324aba5 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/AbstractWindowListener.java @@ -0,0 +1,132 @@ +/******************************************************************************* + * Copyright (c) 2013, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.listeners; + +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IPartService; +import org.eclipse.ui.IPerspectiveListener; +import org.eclipse.ui.IWindowListener; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.IWorkbenchWindow; + +/** + * Abstract window listener implementation. + */ +public abstract class AbstractWindowListener implements IWindowListener { + // The part listener instance + protected final IPartListener2 partListener; + // The perspective listener instance + protected final IPerspectiveListener perspectiveListener; + + // Flag to remember if the initialization is done or not + private boolean initialized = false; + + /** + * Constructor + */ + public AbstractWindowListener() { + // Create the part listener instance + partListener = createPartListener(); + // Create the perspective listener instance + perspectiveListener = createPerspectiveListener(); + } + + /** + * Creates a new part listener instance. + *

              + * Note: The default implementation returns null. + * + * @return The part listener instance or null. + */ + protected IPartListener2 createPartListener() { + return null; + } + + /** + * Creates a new perspective listener instance. + *

              + * Note: The default implementation returns null. + * + * @return The perspective listener instance or null. + */ + protected IPerspectiveListener createPerspectiveListener() { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWindowListener#windowActivated(org.eclipse.ui.IWorkbenchWindow) + */ + @Override + public void windowActivated(IWorkbenchWindow window) { + if (!initialized && window != null) { + windowOpened(window); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWindowListener#windowDeactivated(org.eclipse.ui.IWorkbenchWindow) + */ + @Override + public void windowDeactivated(IWorkbenchWindow window) { + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWindowListener#windowClosed(org.eclipse.ui.IWorkbenchWindow) + */ + @Override + public void windowClosed(IWorkbenchWindow window) { + // On close, remove the listeners from the window + if (window != null) { + if (window.getPartService() != null && partListener != null) { + window.getPartService().removePartListener(partListener); + } + + if (perspectiveListener != null) window.removePerspectiveListener(perspectiveListener); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWindowListener#windowOpened(org.eclipse.ui.IWorkbenchWindow) + */ + @Override + public void windowOpened(IWorkbenchWindow window) { + if (window != null) { + // On open, register the part listener to the window + if (window.getPartService() != null && partListener != null) { + // Get the part service + IPartService service = window.getPartService(); + // Unregister the part listener, just in case + service.removePartListener(partListener); + // Register the part listener + service.addPartListener(partListener); + // Signal the active part to the part listener after registration + IWorkbenchPage page = window.getActivePage(); + if (page != null) { + IWorkbenchPartReference partRef = page.getActivePartReference(); + if (partRef != null) partListener.partActivated(partRef); + } + } + + // Register the perspective listener + if (perspectiveListener != null) { + window.addPerspectiveListener(perspectiveListener); + // Signal the active perspective to the perspective listener after registration + if (window.getActivePage() != null) { + perspectiveListener.perspectiveActivated(window.getActivePage(), window.getActivePage().getPerspective()); + } + } + + initialized = true; + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/WorkbenchPartListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/WorkbenchPartListener.java new file mode 100644 index 00000000000..972c13e02ed --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/WorkbenchPartListener.java @@ -0,0 +1,116 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.listeners; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.contexts.IContextActivation; +import org.eclipse.ui.contexts.IContextService; + +/** + * The part listener implementation. Takes care of + * activation and deactivation of key binding contexts. + */ +public class WorkbenchPartListener implements IPartListener2 { + + // The context activations per workbench part reference + private final Map activations = new HashMap(); + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partBroughtToTop(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partOpened(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partOpened(IWorkbenchPartReference partRef) { + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partClosed(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partClosed(IWorkbenchPartReference partRef) { + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partVisible(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partVisible(IWorkbenchPartReference partRef) { + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partHidden(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partHidden(IWorkbenchPartReference partRef) { + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partActivated(org.eclipse.ui.IWorkbenchPartReference) + */ + @SuppressWarnings("cast") + @Override + public void partActivated(IWorkbenchPartReference partRef) { + if ("org.eclipse.tm.terminal.view.ui.TerminalsView".equals(partRef.getId())) { //$NON-NLS-1$ + IWorkbenchPart part = partRef.getPart(false); + if (part != null && part.getSite() != null) { + IContextService service = (IContextService)part.getSite().getService(IContextService.class); + if (service != null) { + IContextActivation activation = service.activateContext(partRef.getId()); + if (activation != null) { + activations.put(partRef, activation); + } else { + activations.remove(partRef); + } + } + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partDeactivated(org.eclipse.ui.IWorkbenchPartReference) + */ + @SuppressWarnings("cast") + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + if ("org.eclipse.tm.terminal.view.ui.TerminalsView".equals(partRef.getId())) { //$NON-NLS-1$ + IWorkbenchPart part = partRef.getPart(false); + if (part != null && part.getSite() != null) { + IContextService service = (IContextService)part.getSite().getService(IContextService.class); + if (service != null) { + IContextActivation activation = activations.remove(partRef); + if (activation != null) { + service.deactivateContext(activation); + } + } + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IPartListener2#partInputChanged(org.eclipse.ui.IWorkbenchPartReference) + */ + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/WorkbenchWindowListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/WorkbenchWindowListener.java new file mode 100644 index 00000000000..4334d6fc5f4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/listeners/WorkbenchWindowListener.java @@ -0,0 +1,29 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.listeners; + +import org.eclipse.ui.IPartListener2; + +/** + * The window listener implementation. Takes care of the + * management of the global listeners per workbench window. + */ +public class WorkbenchWindowListener extends AbstractWindowListener { + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.listeners.AbstractWindowListener#createPartListener() + */ + @Override + protected IPartListener2 createPartListener() { + return new WorkbenchPartListener(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/DynamicContributionItems.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/DynamicContributionItems.java new file mode 100644 index 00000000000..8a337fbe11d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/DynamicContributionItems.java @@ -0,0 +1,131 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.local.showin; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.ActionContributionItem; +import org.eclipse.jface.action.IAction; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IExternalExecutablesProperties; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.ui.ISelectionService; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.actions.CompoundContributionItem; +import org.eclipse.ui.menus.IWorkbenchContribution; +import org.eclipse.ui.services.IServiceLocator; + +/** + * Dynamic "Show In" contribution items implementation. + */ +public class DynamicContributionItems extends CompoundContributionItem implements IWorkbenchContribution { + // Service locator to located the handler service. + protected IServiceLocator serviceLocator; + // Reference to the local terminal launcher delegate + /* default */ ILauncherDelegate delegate; + + /* (non-Javadoc) + * @see org.eclipse.ui.menus.IWorkbenchContribution#initialize(org.eclipse.ui.services.IServiceLocator) + */ + @Override + public void initialize(IServiceLocator serviceLocator) { + this.serviceLocator = serviceLocator; + + // Get the local terminal launcher delegate + delegate = LauncherDelegateManager.getInstance().getLauncherDelegate("org.eclipse.tm.terminal.connector.local.launcher.local", false); //$NON-NLS-1$ + } + + /* (non-Javadoc) + * @see org.eclipse.ui.actions.CompoundContributionItem#getContributionItems() + */ + @Override + protected IContributionItem[] getContributionItems() { + List items = new ArrayList(); + + if (delegate != null) { + List> l = ExternalExecutablesManager.load(); + if (l != null && !l.isEmpty()) { + for (Map executableData : l) { + String name = executableData.get(IExternalExecutablesProperties.PROP_NAME); + String path = executableData.get(IExternalExecutablesProperties.PROP_PATH); + String args = executableData.get(IExternalExecutablesProperties.PROP_ARGS); + String icon = executableData.get(IExternalExecutablesProperties.PROP_ICON); + + String strTranslate = executableData.get(IExternalExecutablesProperties.PROP_TRANSLATE); + boolean translate = strTranslate != null ? Boolean.parseBoolean(strTranslate) : false; + + if (name != null && !"".equals(name) && path != null && !"".equals(path)) { //$NON-NLS-1$ //$NON-NLS-2$ + IAction action = createAction(name, path, args, translate); + + ImageData id = icon != null ? ExternalExecutablesManager.loadImage(icon) : null; + if (id != null) { + ImageDescriptor desc = ImageDescriptor.createFromImageData(id); + if (desc != null) action.setImageDescriptor(desc); + } + + IContributionItem item = new ActionContributionItem(action); + items.add(item); + } + } + } + } + + return items.toArray(new IContributionItem[items.size()]); + } + + /** + * Creates the action to execute. + * + * @param label The label. Must not be null. + * @param path The executable path. Must not be null. + * @param args The executable arguments or null. + * @param translate Translate backslashes. + * + * @return The action to execute. + */ + protected IAction createAction(final String label, final String path, final String args, final boolean translate) { + Assert.isNotNull(label); + Assert.isNotNull(path); + + IAction action = new Action(label) { + @Override + public void run() { + Assert.isNotNull(delegate); + + ISelectionService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getSelectionService(); + ISelection selection = service != null ? service.getSelection() : null; + if (selection != null && selection.isEmpty()) selection = null; + + Map properties = new HashMap(); + properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, delegate.getId()); + if (selection != null) properties.put(ITerminalsConnectorConstants.PROP_SELECTION, selection); + properties.put(ITerminalsConnectorConstants.PROP_PROCESS_PATH, path); + if (args != null) properties.put(ITerminalsConnectorConstants.PROP_PROCESS_ARGS, args); + properties.put(ITerminalsConnectorConstants.PROP_TRANSLATE_BACKSLASHES_ON_PASTE, Boolean.valueOf(translate)); + + delegate.execute(properties, null); + } + }; + + return action; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/ExternalExecutablesDialog.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/ExternalExecutablesDialog.java new file mode 100644 index 00000000000..61150391150 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/ExternalExecutablesDialog.java @@ -0,0 +1,462 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.local.showin; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.IDialogConstants; +import org.eclipse.jface.dialogs.TrayDialog; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.ScrolledComposite; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +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.Button; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Shell; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.terminal.view.ui.help.IContextHelpIds; +import org.eclipse.tm.terminal.view.ui.interfaces.IExternalExecutablesProperties; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.PlatformUI; +import org.osgi.framework.Bundle; + +/** + * External executables dialog implementation. + */ +public class ExternalExecutablesDialog extends TrayDialog { + private String contextHelpId = null; + private final boolean edit; + + private Text name; + /* default */ Text path; + private Text args; + /* default */ Text icon; + private Button translate; + + /* default */ String last_filter_path = null; + /* default */ String last_filter_icon = null; + + private Map executableData; + + /** + * Constructor. + * + * @param shell The parent shell or null. + */ + public ExternalExecutablesDialog(Shell shell, boolean edit) { + super(shell); + this.edit = edit; + + this.contextHelpId = IContextHelpIds.EXTERNAL_EXECUTABLES_DIALOG; + setHelpAvailable(true); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) + */ + @Override + protected final Control createDialogArea(Composite parent) { + if (contextHelpId != null) { + PlatformUI.getWorkbench().getHelpSystem().setHelp(parent, contextHelpId); + } + + // Let the super implementation create the dialog area control + Control control = super.createDialogArea(parent); + // Setup the inner panel as scrollable composite + if (control instanceof Composite) { + ScrolledComposite sc = new ScrolledComposite((Composite)control, SWT.V_SCROLL); + + GridLayout layout = new GridLayout(1, true); + layout.marginHeight = 0; layout.marginWidth = 0; + layout.verticalSpacing = 0; layout.horizontalSpacing = 0; + + sc.setLayout(layout); + sc.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true)); + + sc.setExpandHorizontal(true); + sc.setExpandVertical(true); + + Composite composite = new Composite(sc, SWT.NONE); + composite.setLayout(new GridLayout()); + + // Setup the dialog area content + createDialogAreaContent(composite); + + sc.setContent(composite); + sc.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT)); + + // Return the scrolled composite as new dialog area control + control = sc; + } + + return control; + } + + /** + * Creates the dialog area content. + * + * @param parent The parent composite. Must not be null. + */ + protected void createDialogAreaContent(Composite parent) { + Assert.isNotNull(parent); + + setDialogTitle(edit ? Messages.ExternalExecutablesDialog_title_edit : Messages.ExternalExecutablesDialog_title_add); + + Composite panel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + panel.setLayout(layout); + GridData layoutData = new GridData(SWT.FILL, SWT.CENTER, true, true); + layoutData.widthHint = convertWidthInCharsToPixels(50); + panel.setLayoutData(layoutData); + + Label label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ExternalExecutablesDialog_field_name); + layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + label.setLayoutData(layoutData); + + name = new Text(panel, SWT.HORIZONTAL | SWT.SINGLE | SWT.BORDER); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + layoutData.widthHint = convertWidthInCharsToPixels(30); + name.setLayoutData(layoutData); + name.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + validate(); + } + }); + + label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ExternalExecutablesDialog_field_path); + layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + label.setLayoutData(layoutData); + + Composite panel2 = new Composite(panel, SWT.NONE); + layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + panel2.setLayout(layout); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + panel2.setLayoutData(layoutData); + + path = new Text(panel2, SWT.HORIZONTAL | SWT.SINGLE | SWT.BORDER); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + layoutData.widthHint = convertWidthInCharsToPixels(30); + path.setLayoutData(layoutData); + path.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + validate(); + } + }); + + Button button = new Button(panel2, SWT.PUSH); + button.setText(Messages.ExternalExecutablesDialog_button_browse); + layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + layoutData.widthHint = convertWidthInCharsToPixels(10); + button.setLayoutData(layoutData); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); + + String selectedFile = path.getText(); + if (selectedFile != null && selectedFile.trim().length() > 0) { + IPath filePath = new Path(selectedFile); + // If the selected file points to an directory, use the directory as is + IPath filterPath = filePath.toFile().isDirectory() ? filePath : filePath.removeLastSegments(1); + while (filterPath != null && filterPath.segmentCount() > 1 && !filterPath.toFile().exists()) { + filterPath = filterPath.removeLastSegments(1); + } + String filterFileName = filePath.toFile().isDirectory() || !filePath.toFile().exists() ? null : filePath.lastSegment(); + + if (filterPath != null && !filterPath.isEmpty()) dialog.setFilterPath(filterPath.toString()); + if (filterFileName != null) dialog.setFileName(filterFileName); + } else { + String workspace = null; + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + workspace = org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString(); + } + + String filterPath = last_filter_path != null ? last_filter_path : workspace; + dialog.setFilterPath(filterPath); + } + + selectedFile = dialog.open(); + if (selectedFile != null) { + last_filter_path = dialog.getFilterPath(); + path.setText(selectedFile); + } + } + }); + + label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ExternalExecutablesDialog_field_args); + layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + label.setLayoutData(layoutData); + + args = new Text(panel, SWT.HORIZONTAL | SWT.SINGLE | SWT.BORDER); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + layoutData.widthHint = convertWidthInCharsToPixels(30); + args.setLayoutData(layoutData); + args.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + validate(); + } + }); + + label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.ExternalExecutablesDialog_field_icon); + layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + label.setLayoutData(layoutData); + + panel2 = new Composite(panel, SWT.NONE); + layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + panel2.setLayout(layout); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + panel2.setLayoutData(layoutData); + + icon = new Text(panel2, SWT.HORIZONTAL | SWT.SINGLE | SWT.BORDER); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + layoutData.widthHint = convertWidthInCharsToPixels(30); + icon.setLayoutData(layoutData); + icon.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + validate(); + } + }); + + button = new Button(panel2, SWT.PUSH); + button.setText(Messages.ExternalExecutablesDialog_button_browse); + layoutData = new GridData(SWT.BEGINNING, SWT.CENTER, false, false); + layoutData.widthHint = convertWidthInCharsToPixels(10); + button.setLayoutData(layoutData); + button.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(getShell(), SWT.OPEN); + + String selectedFile = icon.getText(); + if (selectedFile != null && selectedFile.trim().length() > 0) { + IPath filePath = new Path(selectedFile); + // If the selected file points to an directory, use the directory as is + IPath filterPath = filePath.toFile().isDirectory() ? filePath : filePath.removeLastSegments(1); + while (filterPath != null && filterPath.segmentCount() > 1 && !filterPath.toFile().exists()) { + filterPath = filterPath.removeLastSegments(1); + } + String filterFileName = filePath.toFile().isDirectory() || !filePath.toFile().exists() ? null : filePath.lastSegment(); + + if (filterPath != null && !filterPath.isEmpty()) dialog.setFilterPath(filterPath.toString()); + if (filterFileName != null) dialog.setFileName(filterFileName); + } else { + String workspace = null; + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + workspace = org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString(); + } + + String filterPath = last_filter_icon != null ? last_filter_icon : workspace; + dialog.setFilterPath(filterPath); + } + + selectedFile = dialog.open(); + if (selectedFile != null) { + last_filter_icon = dialog.getFilterPath(); + icon.setText(selectedFile); + } + } + }); + + translate = new Button(panel, SWT.CHECK); + translate.setText(Messages.ExternalExecutablesDialog_field_translate); + layoutData = new GridData(SWT.FILL, SWT.TOP, true, false); + layoutData.horizontalSpan = 2; + translate.setLayoutData(layoutData); + translate.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + validate(); + } + }); + + if (executableData != null) { + String value = executableData.get(IExternalExecutablesProperties.PROP_NAME); + name.setText(value != null && !"".equals(value.trim()) ? value : ""); //$NON-NLS-1$ //$NON-NLS-2$ + value = executableData.get(IExternalExecutablesProperties.PROP_PATH); + path.setText(value != null && !"".equals(value.trim()) ? value : ""); //$NON-NLS-1$ //$NON-NLS-2$ + value = executableData.get(IExternalExecutablesProperties.PROP_ARGS); + args.setText(value != null && !"".equals(value.trim()) ? value : ""); //$NON-NLS-1$ //$NON-NLS-2$ + value = executableData.get(IExternalExecutablesProperties.PROP_ICON); + icon.setText(value != null && !"".equals(value.trim()) ? value : ""); //$NON-NLS-1$ //$NON-NLS-2$ + value = executableData.get(IExternalExecutablesProperties.PROP_TRANSLATE); + translate.setSelection(value != null ? Boolean.parseBoolean(value) : false); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.TrayDialog#createButtonBar(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createButtonBar(Composite parent) { + Control control = super.createButtonBar(parent); + validate(); + return control; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#createButton(org.eclipse.swt.widgets.Composite, int, java.lang.String, boolean) + */ + @Override + protected Button createButton(Composite parent, int id, String label, boolean defaultButton) { + if (IDialogConstants.OK_ID == id && !edit) { + label = Messages.ExternalExecutablesDialog_button_add; + } + return super.createButton(parent, id, label, defaultButton); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.Dialog#okPressed() + */ + @Override + protected void okPressed() { + if (name != null && path != null) { + // Extract the executable properties + if (executableData == null) executableData = new HashMap(); + + String value = name.getText(); + if (value != null && !"".equals(value.trim())) { //$NON-NLS-1$ + executableData.put(IExternalExecutablesProperties.PROP_NAME, value); + } else { + executableData.remove(IExternalExecutablesProperties.PROP_NAME); + } + + value = path.getText(); + if (value != null && !"".equals(value.trim())) { //$NON-NLS-1$ + executableData.put(IExternalExecutablesProperties.PROP_PATH, value); + } else { + executableData.remove(IExternalExecutablesProperties.PROP_PATH); + } + + value = args.getText(); + if (value != null && !"".equals(value.trim())) { //$NON-NLS-1$ + executableData.put(IExternalExecutablesProperties.PROP_ARGS, value); + } else { + executableData.remove(IExternalExecutablesProperties.PROP_ARGS); + } + + value = icon.getText(); + if (value != null && !"".equals(value.trim())) { //$NON-NLS-1$ + executableData.put(IExternalExecutablesProperties.PROP_ICON, value); + } else { + executableData.remove(IExternalExecutablesProperties.PROP_ICON); + } + + if (translate.getSelection()) { + executableData.put(IExternalExecutablesProperties.PROP_TRANSLATE, Boolean.TRUE.toString()); + } else { + executableData.remove(IExternalExecutablesProperties.PROP_TRANSLATE); + } + } else { + executableData = null; + } + super.okPressed(); + } + + @Override + protected void cancelPressed() { + // If the user pressed cancel, the dialog needs to return null + executableData = null; + super.cancelPressed(); + } + + /** + * Returns the executable properties the user entered. + * + * @return The executable properties or null. + */ + public Map getExecutableData() { + return executableData; + } + + /** + * Set or reset the executable properties. This method has effect + * only if called before opening the dialog. + * + * @param data The executable properties or null. + */ + public void setExecutableData(Map data) { + if (data == null) { + executableData = null; + } else { + executableData = new HashMap(data); + } + } + + /** + * Validate the dialog. + */ + public void validate() { + boolean valid = true; + + if (name != null && !name.isDisposed()) { + valid = !"".equals(name.getText()); //$NON-NLS-1$ + } + + if (path != null && !path.isDisposed()) { + String value = path.getText(); + if (!"".equals(value)) { //$NON-NLS-1$ + File f = new File(value); + valid |= f.isAbsolute() && f.canRead(); + } else { + valid = false; + } + } + + if (icon != null && !icon.isDisposed()) { + String value = icon.getText(); + if (!"".equals(value)) { //$NON-NLS-1$ + File f = new File(value); + valid |= f.isAbsolute() && f.canRead(); + } + } + + Button okButton = getButton(IDialogConstants.OK_ID); + if (okButton != null) okButton.setEnabled(valid); + } + + /** + * Sets the title for this dialog. + * + * @param title The title. + */ + public void setDialogTitle(String title) { + if (getShell() != null && !getShell().isDisposed()) { + getShell().setText(title); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/ExternalExecutablesManager.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/ExternalExecutablesManager.java new file mode 100644 index 00000000000..b973edb3215 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/local/showin/ExternalExecutablesManager.java @@ -0,0 +1,296 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.local.showin; + +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.StringTokenizer; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.graphics.ImageLoader; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.IExternalExecutablesProperties; +import org.eclipse.tm.terminal.view.ui.internal.ExternalExecutablesState; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.services.ISourceProviderService; + +/** + * External executables manager implementation. + */ +public class ExternalExecutablesManager { + // Flag to indicate if we have searched for git bash already + private static boolean gitBashSearchDone = false; + + /** + * Loads the list of all saved external executables. + * + * @return The list of all saved external executables or null. + */ + public static List> load() { + List> l = new ArrayList>(); + + IPath stateLocation = UIPlugin.getDefault().getStateLocation(); + if (stateLocation != null) { + File f = stateLocation.append(".executables/data.properties").toFile(); //$NON-NLS-1$ + if (f.canRead()) { + FileReader r = null; + + try { + Properties data = new Properties(); + r= new FileReader(f); + data.load(r); + + Map> c = new HashMap>(); + for (String name : data.stringPropertyNames()) { + if (name == null || name.indexOf('.') == -1) continue; + int ix = name.indexOf('.'); + String n = name.substring(0, ix); + String k = (ix + 1) < name.length() ? name.substring(ix + 1) : null; + if (n == null || k == null) continue; + + Integer i = null; + try { i = Integer.decode(n); } catch (NumberFormatException e) { /* ignored on purpose */ } + if (i == null) continue; + + Map m = c.get(i); + if (m == null) { + m = new HashMap(); + c.put(i, m); + } + Assert.isNotNull(m); + + m.put(k, data.getProperty(name)); + } + + List k = new ArrayList(c.keySet()); + Collections.sort(k); + for (Integer i : k) { + Map m = c.get(i); + if (m != null && !m.isEmpty()) l.add(m); + } + } catch (Exception e) { + if (Platform.inDebugMode()) { + e.printStackTrace(); + } + } finally { + if (r != null) try { r.close(); } catch (IOException e) { /* ignored on purpose */ } + } + } + } + + // Lookup git bash (Windows Hosts only) + if (!gitBashSearchDone && Platform.OS_WIN32.equals(Platform.getOS())) { + // Check the existing entries first + // Find a entry labeled "Git Bash" + Map m = null; + for (Map candidate : l) { + String name = candidate.get(IExternalExecutablesProperties.PROP_NAME); + if ("Git Bash".equals(name)) { //$NON-NLS-1$ + m = candidate; + break; + } + } + + // If not found in the existing entries, check the path + if (m == null) { + String gitPath = null; + String iconPath = null; + + String path = System.getenv("PATH"); //$NON-NLS-1$ + if (path != null) { + StringTokenizer tokenizer = new StringTokenizer(path, ";"); //$NON-NLS-1$ + while (tokenizer.hasMoreTokens()) { + String token = tokenizer.nextToken(); + File f = new File(token, "git.exe"); //$NON-NLS-1$ + if (f.canRead()) { + File f2 = new File(f.getParentFile().getParentFile(), "bin/sh.exe"); //$NON-NLS-1$ + if (f2.canExecute()) { + gitPath = f2.getAbsolutePath(); + } + + iconPath = getGitIconPath(f.getParentFile().getParentFile()); + + break; + } + } + } + + // if it is not found in the PATH, check the default install locations + if (gitPath == null) { + File f = new File("C:/Program Files (x86)/Git/bin/sh.exe"); //$NON-NLS-1$ + if (!f.exists()) { + f = new File("C:/Program Files/Git/bin/sh.exe"); //$NON-NLS-1$ + } + + if (f.exists() && f.canExecute()) { + gitPath = f.getAbsolutePath(); + iconPath = getGitIconPath(f.getParentFile().getParentFile()); + } + } + + if (gitPath != null) { + m = new HashMap(); + m.put(IExternalExecutablesProperties.PROP_NAME, "Git Bash"); //$NON-NLS-1$ + m.put(IExternalExecutablesProperties.PROP_PATH, gitPath); + m.put(IExternalExecutablesProperties.PROP_ARGS, "--login -i"); //$NON-NLS-1$ + if (iconPath != null) m.put(IExternalExecutablesProperties.PROP_ICON, iconPath); + m.put(IExternalExecutablesProperties.PROP_TRANSLATE, Boolean.TRUE.toString()); + + l.add(m); + save(l); + } + } + + // Do not search again for git bash while the session is running + gitBashSearchDone = true; + } + + return l; + } + + private static String getGitIconPath(File parent) { + File f = new File(parent, "etc/git.ico"); //$NON-NLS-1$ + if (f.canRead()) { + return f.getAbsolutePath(); + } + + // check for icon in newer versions of Git for Windows 32 bit + f = new File(parent, "mingw32/share/git/git-for-windows.ico"); //$NON-NLS-1$ + if (f.canRead()) { + return f.getAbsolutePath(); + } + + // check for icon in newer versions of Git for Windows 64 bit + f = new File(parent, "mingw64/share/git/git-for-windows.ico"); //$NON-NLS-1$ + if (f.canRead()) { + return f.getAbsolutePath(); + } + + return null; + } + + /** + * Saves the list of external executables. + * + * @param l The list of external executables or null. + */ + @SuppressWarnings("cast") + public static void save(List> l) { + ISourceProviderService sourceProviderService = (ISourceProviderService) PlatformUI.getWorkbench().getService(ISourceProviderService.class); + ExternalExecutablesState stateService = (ExternalExecutablesState) sourceProviderService.getSourceProvider(ExternalExecutablesState.CONFIGURED_STATE); + + IPath stateLocation = UIPlugin.getDefault().getStateLocation(); + if (stateLocation != null) { + File f = stateLocation.append(".executables/data.properties").toFile(); //$NON-NLS-1$ + if (f.isFile() && (l == null || l.isEmpty())) { + @SuppressWarnings("unused") + boolean s = f.delete(); + + if (stateService != null) stateService.disable(); + } else { + FileWriter w = null; + + try { + Properties data = new Properties(); + for (int i = 0; i < l.size(); i++) { + Map m = l.get(i); + for (Entry e : m.entrySet()) { + String key = Integer.toString(i) + "." + e.getKey(); //$NON-NLS-1$ + data.setProperty(key, e.getValue()); + } + } + + if (!f.exists()) { + @SuppressWarnings("unused") + boolean s = f.getParentFile().mkdirs(); + s = f.createNewFile(); + } + w = new FileWriter(f); + data.store(w, null); + + if (stateService != null) stateService.enable(); + } catch (Exception e) { + if (Platform.inDebugMode()) { + e.printStackTrace(); + } + } finally { + if (w != null) { + try { + w.flush(); + w.close(); + } catch (IOException e) { + /* ignored on purpose */ + } + } + } + } + } + } + + /** + * Loads the image data suitable for showing an icon in a menu + * (16 x 16, 8bit depth) from the given file. + * + * @param path The image file path. Must not be null. + * @return The image data or null. + */ + public static ImageData loadImage(String path) { + Assert.isNotNull(path); + + ImageData id = null; + ImageData biggest = null; + + ImageLoader loader = new ImageLoader(); + ImageData[] data = loader.load(path); + + if (data != null) { + for (ImageData d : data) { + if (d.height == 16 && d.width == 16) { + if (id == null || id.height != 16 && id.width != 16) { + id = d; + } else if (d.depth < id.depth && d.depth >= 8){ + id = d; + } + } else { + if (id == null) { + id = d; + biggest = d; + } else if (id.height != 16 && d.height < id.height && id.width != 16 && d.width < id.width) { + id = d; + } else if (biggest == null || d.height > biggest.height && d.width > biggest.width) { + biggest = d; + } + } + } + } + + // if the icon is still to big -> downscale the biggest + if (id != null && id.height > 16 && id.width > 16) { + id = biggest.scaledTo(16, 16); + } + + return id; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/manager/ConsoleManager.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/manager/ConsoleManager.java new file mode 100644 index 00000000000..f81cb25dca0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/manager/ConsoleManager.java @@ -0,0 +1,638 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.manager; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.IPreferenceKeys; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.interfaces.IUIConstants; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; +import org.eclipse.tm.terminal.view.ui.view.TerminalsView; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IPartService; +import org.eclipse.ui.IPerspectiveDescriptor; +import org.eclipse.ui.IPerspectiveListener; +import org.eclipse.ui.IViewPart; +import org.eclipse.ui.IViewReference; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PerspectiveAdapter; +import org.eclipse.ui.PlatformUI; + +/** + * Terminal console manager. + */ +public class ConsoleManager { + + // Constant to indicate any secondary id is acceptable + private final static String ANY_SECONDARY_ID = new String("*"); //$NON-NLS-1$ + + // Reference to the perspective listener instance + private final IPerspectiveListener perspectiveListener; + + // Internal perspective listener implementation + static class ConsoleManagerPerspectiveListener extends PerspectiveAdapter { + private final List references = new ArrayList(); + + /* (non-Javadoc) + * @see org.eclipse.ui.PerspectiveAdapter#perspectiveActivated(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor) + */ + @Override + public void perspectiveActivated(IWorkbenchPage page, IPerspectiveDescriptor perspective) { + // If the old references list is empty, just return + if (references.isEmpty()) return; + // Create a copy of the old view references list + List oldReferences = new ArrayList(references); + + // Get the current list of view references + List references = new ArrayList(Arrays.asList(page.getViewReferences())); + for (IViewReference reference : oldReferences) { + if (references.contains(reference)) continue; + // Previous visible terminals console view reference, make visible again + try { + page.showView(reference.getId(), reference.getSecondaryId(), IWorkbenchPage.VIEW_VISIBLE); + } catch (PartInitException e) { /* Failure on part instantiation is ignored */ } + } + + } + + /* (non-Javadoc) + * @see org.eclipse.ui.PerspectiveAdapter#perspectivePreDeactivate(org.eclipse.ui.IWorkbenchPage, org.eclipse.ui.IPerspectiveDescriptor) + */ + @Override + public void perspectivePreDeactivate(IWorkbenchPage page, IPerspectiveDescriptor perspective) { + references.clear(); + for (IViewReference reference : page.getViewReferences()) { + IViewPart part = reference.getView(false); + if (part instanceof TerminalsView && !references.contains(reference)) { + references.add(reference); + } + } + } + } + + // Reference to the part listener instance + private final IPartListener2 partListener; + + // The ids of the last activated terminals view + /* default */ String lastActiveViewId = null; + /* default */ String lastActiveSecondaryViewId = null; + + // Internal part listener implementation + class ConsoleManagerPartListener implements IPartListener2 { + + @Override + public void partActivated(IWorkbenchPartReference partRef) { + IWorkbenchPart part = partRef.getPart(false); + if (part instanceof ITerminalsView) { + lastActiveViewId = ((ITerminalsView)part).getViewSite().getId(); + lastActiveSecondaryViewId = ((ITerminalsView)part).getViewSite().getSecondaryId(); + //System.out.println("Terminals view activated: id = " + lastActiveViewId + ", secondary id = " + lastActiveSecondaryViewId); //$NON-NLS-1$ //$NON-NLS-2$ + } + } + + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + } + + @Override + public void partClosed(IWorkbenchPartReference partRef) { + } + + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + } + + @Override + public void partOpened(IWorkbenchPartReference partRef) { + } + + @Override + public void partHidden(IWorkbenchPartReference partRef) { + } + + @Override + public void partVisible(IWorkbenchPartReference partRef) { + } + + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + } + } + + /* + * Thread save singleton instance creation. + */ + private static class LazyInstanceHolder { + public static ConsoleManager fInstance = new ConsoleManager(); + } + + /** + * Returns the singleton instance for the console manager. + */ + public static ConsoleManager getInstance() { + return LazyInstanceHolder.fInstance; + } + + /** + * Constructor. + */ + ConsoleManager() { + super(); + + perspectiveListener = new ConsoleManagerPerspectiveListener(); + partListener = new ConsoleManagerPartListener(); + + if (PlatformUI.isWorkbenchRunning() && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) { + PlatformUI.getWorkbench().getActiveWorkbenchWindow().addPerspectiveListener(perspectiveListener); + + IPartService service = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getPartService(); + service.addPartListener(partListener); + } + } + + /** + * Returns the active workbench window page if the workbench is still running. + * + * @return The active workbench window page or null + */ + private final IWorkbenchPage getActiveWorkbenchPage() { + // To lookup the console view, the workbench must be still running + if (PlatformUI.isWorkbenchRunning() && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) { + return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + } + return null; + } + + /** + * Returns the console view if available within the active workbench window page. + *

              + * Note: The method must be called within the UI thread. + * + * @param id The terminals console view id or null to show the default terminals console view. + * @param secondaryId The terminals console view secondary id or null. + * + * @return The console view instance if available or null otherwise. + */ + public ITerminalsView findConsoleView(String id, String secondaryId) { + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + ITerminalsView view = null; + + // Get the active workbench page + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + // Look for the view + IViewPart part = getTerminalsViewWithSecondaryId(id != null ? id : IUIConstants.ID, secondaryId, true); + // Check the interface + if (part instanceof ITerminalsView) { + view = (ITerminalsView)part; + } + } + + return view; + } + + /** + * Search and return a terminal view with a specific secondary id + * + * @param id The terminals console view id. Must not be null. + * @param secondaryId The terminals console view secondary id or null. + * @param restore True if to try to restore the view, false otherwise. + * + * @return The terminals console view instance or null if not found. + */ + private IViewPart getTerminalsViewWithSecondaryId(String id, String secondaryId, boolean restore) { + Assert.isNotNull(id); + + for (IViewReference ref : getActiveWorkbenchPage().getViewReferences()) { + if (ref.getId().equals(id)) { + if (ANY_SECONDARY_ID.equals(secondaryId) + || secondaryId == null && ref.getSecondaryId() == null + || secondaryId != null && secondaryId.equals(ref.getSecondaryId())) { + return ref.getView(restore); + } + } + } + return null; + } + + /** + * Search and return the active terminals view. + * + * @param id The terminals console view id. Must not be null. + * @param secondaryId The terminals console view secondary id or null. + * @return The terminals console view instance or null if not found. + */ + private IViewPart getActiveTerminalsView(String id, String secondaryId) { + Assert.isNotNull(id); + + IViewPart part = null; + + if (id.equals(lastActiveViewId)) { + if (secondaryId == null || ANY_SECONDARY_ID.equals(secondaryId) || secondaryId.equals(lastActiveSecondaryViewId)) { + part = getTerminalsViewWithSecondaryId(lastActiveViewId, lastActiveSecondaryViewId, false); + } + } + + if (part == null) { + part = getTerminalsViewWithSecondaryId(id, secondaryId, true); + if (part != null) { + lastActiveViewId = part.getViewSite().getId(); + lastActiveSecondaryViewId = part.getViewSite().getSecondaryId(); + } + } + + return part; + } + + /** + * Return a new secondary id to use, based on the number of open terminal views. + * + * @param id The terminals console view id. Must not be null. + * @return The next secondary id, or null if it is the first one + * @since 4.1 + */ + public String getNextTerminalSecondaryId(String id) { + Assert.isNotNull(id); + + Map terminalViews = new HashMap(); + + int maxNumber = 0; + for (IViewReference ref : getActiveWorkbenchPage().getViewReferences()) { + if (ref.getId().equals(id)) { + if (ref.getSecondaryId() != null) { + terminalViews.put(ref.getSecondaryId(), ref); + int scondaryIdInt = Integer.parseInt(ref.getSecondaryId()); + if (scondaryIdInt > maxNumber) { + maxNumber = scondaryIdInt; + } + } + else { + // add the one with secondaryId == null with 0 by default + terminalViews.put(Integer.toString(0), ref); + } + } + } + if (terminalViews.size() == 0) { + return null; + } + + int i = 0; + for (; i < maxNumber; i++) { + String secondaryIdStr = Integer.toString(i); + if (!terminalViews.keySet().contains(secondaryIdStr)) { + // found a free slot + if (i == 0) + return null; + return Integer.toString(i); + } + } + // add a new one + return Integer.toString(i + 1); + } + + /** + * Show the terminals console view specified by the given id. + *

              + * Note: The method must be called within the UI thread. + * + * @param id The terminals console view id or null to show the default terminals console view. + */ + public IViewPart showConsoleView(String id, String secondaryId) { + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + // Get the active workbench page + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + try { + // show the view + IViewPart part = getActiveTerminalsView(id != null ? id : IUIConstants.ID, secondaryId); + if (part == null) part = page.showView(id != null ? id : IUIConstants.ID, secondaryId, IWorkbenchPage.VIEW_ACTIVATE); + // and force the view to the foreground + page.bringToTop(part); + return part; + } + catch (PartInitException e) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), e.getLocalizedMessage(), e); + UIPlugin.getDefault().getLog().log(status); + } + } + return null; + } + + /** + * Bring the terminals console view, specified by the given id, to the top of the view stack. + * + * @param id The terminals console view id or null to show the default terminals console view. + * @param secondaryId The terminals console view secondary id or null. + * @param activate If true activate the console view. + */ + private IViewPart bringToTop(String id, String secondaryId, boolean activate) { + // Get the active workbench page + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + // get (last) active terminal view + IViewPart activePart = getActiveTerminalsView(id != null ? id : IUIConstants.ID, secondaryId); + if (activePart == null) { + // Create a new one + IViewPart newPart = showConsoleView(id != null ? id : IUIConstants.ID, getSecondaryId(secondaryId, id)); + return newPart; + } + + if (activate) page.activate(activePart); + else page.bringToTop(activePart); + + return activePart; + } + return null; + } + + /** + * Return the secondary id to use. + * @param secondaryId + * @param id + * @return the secondaryId argument is not null, or *, otherwise use the auto generated secondary id. + */ + private String getSecondaryId(String secondaryId, String id){ + if(secondaryId==null || ANY_SECONDARY_ID.equals(secondaryId)){ + return getNextTerminalSecondaryId(id != null ? id : IUIConstants.ID); + } + + return secondaryId; + } + + /** + * Opens the console with the given title and connector. + *

              + * Note: The method must be called within the UI thread. + * + * @param id The terminals console view id or null to show the default terminals console view. + * @param title The console title. Must not be null. + * @param encoding The terminal encoding or null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * @param flags The flags controlling how the console is opened or null to use defaults. + */ + public CTabItem openConsole(String id, String title, String encoding, ITerminalConnector connector, Object data, Map flags) { + return openConsole(id, ANY_SECONDARY_ID, title, encoding, connector, data, flags); + } + + /** + * Opens the console with the given title and connector. + *

              + * Note: The method must be called within the UI thread. + * + * @param id The terminals console view id or null to show the default terminals console view. + * @param secondaryId The terminals console view secondary id or null. + * @param title The console title. Must not be null. + * @param encoding The terminal encoding or null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * @param flags The flags controlling how the console is opened or null to use defaults. + */ + @SuppressWarnings("cast") + public CTabItem openConsole(String id, String secondaryId, String title, String encoding, ITerminalConnector connector, Object data, Map flags) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + // Get the flags handled by the openConsole method itself + boolean activate = flags != null && flags.containsKey("activate") ? flags.get("activate").booleanValue() : false; //$NON-NLS-1$ //$NON-NLS-2$ + boolean forceNew = flags != null && flags.containsKey(ITerminalsConnectorConstants.PROP_FORCE_NEW) ? flags.get(ITerminalsConnectorConstants.PROP_FORCE_NEW).booleanValue() : false; + + // Make the consoles view visible + IViewPart part = bringToTop(id, secondaryId, activate); + if (!(part instanceof ITerminalsView)) return null; + // Cast to the correct type + ITerminalsView view = (ITerminalsView)part; + + // Get the tab folder manager associated with the view + TabFolderManager manager = (TabFolderManager) view.getAdapter(TabFolderManager.class); + if (manager == null) return null; + + // Lookup an existing console first + String secId = ((IViewSite)part.getSite()).getSecondaryId(); + CTabItem item = findConsole(id, secId, title, connector, data); + + // Switch to the tab folder page _before_ calling TabFolderManager#createItem(...). + // The createItem(...) method invokes the corresponding connect and this may take + // a while if connecting to a remote host. To allow a "Connecting..." decoration, + // the tab folder page needs to be visible. + view.switchToTabFolderControl(); + + // If no existing console exist or forced -> Create the tab item + if (item == null || forceNew) { + // If configured, check all existing tab items if they are associated + // with terminated consoles + if (UIPlugin.getScopedPreferences().getBoolean(IPreferenceKeys.PREF_REMOVE_TERMINATED_TERMINALS)) { + // Remote all terminated tab items. This will invoke the + // tab's dispose listener. + manager.removeTerminatedItems(); + // Switch back to the tab folder control as removeTerminatedItems() + // may have triggered the switch to the empty space control. + view.switchToTabFolderControl(); + } + + // Create a new tab item + item = manager.createTabItem(title, encoding, connector, data, flags); + } + // If still null, something went wrong + if (item == null) return null; + + // Make the item the active console + manager.bringToTop(item); + + // Make sure the terminals view has the focus after opening a new terminal + view.setFocus(); + + // Return the tab item of the opened console + return item; + } + + /** + * Lookup a console with the given title and the given terminal connector. + *

              + * Note: The method must be called within the UI thread. + * Note: The method will handle unified console titles itself. + * + * @param id The terminals console view id or null to show the default terminals console view. + * @param secondaryId The terminals console view secondary id or null. + * @param title The console title. Must not be null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * + * @return The corresponding console tab item or null. + */ + @SuppressWarnings("cast") + public CTabItem findConsole(String id, String secondaryId, String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + // Get the console view + ITerminalsView view = findConsoleView(id, secondaryId); + if (view == null) return null; + + // Get the tab folder manager associated with the view + TabFolderManager manager = (TabFolderManager) view.getAdapter(TabFolderManager.class); + if (manager == null) return null; + + return manager.findTabItem(title, connector, data); + } + + /** + * Lookup a console which is assigned with the given terminal control. + *

              + * Note: The method must be called within the UI thread. + * + * @param control The terminal control. Must not be null. + * @return The corresponding console tab item or null. + */ + @SuppressWarnings("cast") + public CTabItem findConsole(ITerminalControl control) { + Assert.isNotNull(control); + + CTabItem item = null; + + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + for (IViewReference ref : page.getViewReferences()) { + IViewPart part = ref != null ? ref.getView(false) : null; + if (part instanceof ITerminalsView) { + CTabFolder tabFolder = (CTabFolder) part.getAdapter(CTabFolder.class); + if (tabFolder == null) continue; + CTabItem[] candidates = tabFolder.getItems(); + for (CTabItem candidate : candidates) { + Object data = candidate.getData(); + if (data instanceof ITerminalControl && control.equals(data)) { + item = candidate; + break; + } + } + } + if (item != null) break; + } + } + + return item; + } + + /** + * Search all console views for the one that contains a specific connector. + *

              + * Note: The method will handle unified console titles itself. + * + * @param id The terminals console view id or null to show the default terminals console view. + * @param title The console title. Must not be null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * + * @return The corresponding console tab item or null. + */ + @SuppressWarnings("cast") + private CTabItem findConsoleForTerminalConnector(String id, String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + + IWorkbenchPage page = getActiveWorkbenchPage(); + if (page != null) { + IViewReference[] refs = page.getViewReferences(); + for (IViewReference ref : refs) { + if (ref.getId().equals(id)) { + IViewPart part = ref.getView(true); + if (part instanceof ITerminalsView) { + // Get the tab folder manager associated with the view + TabFolderManager manager = (TabFolderManager) part.getAdapter(TabFolderManager.class); + if (manager == null) { + continue; + } + CTabItem item = manager.findTabItem(title, connector, data); + if (item != null) { + return item; + } + } + } + } + } + return null; + } + + /** + * Close the console with the given title and the given terminal connector. + *

              + * Note: The method must be called within the UI thread. + * Note: The method will handle unified console titles itself. + * + * @param title The console title. Must not be null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + */ + public void closeConsole(String id, String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + // Lookup the console with this connector + CTabItem console = findConsoleForTerminalConnector(id, title, connector, data); + // If found, dispose the console + if (console != null) { + console.dispose(); + } + } + + /** + * Terminate (disconnect) the console with the given title and the given terminal connector. + *

              + * Note: The method must be called within the UI thread. + * Note: The method will handle unified console titles itself. + * + * @param title The console title. Must not be null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + */ + public void terminateConsole(String id, String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + // Lookup the console + CTabItem console = findConsoleForTerminalConnector(id, title, connector, data); + // If found, disconnect the console + if (console != null && !console.isDisposed()) { + ITerminalViewControl terminal = (ITerminalViewControl)console.getData(); + if (terminal != null && !terminal.isDisposed()) { + terminal.disconnectTerminal(); + } + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/nls/Messages.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/nls/Messages.java new file mode 100644 index 00000000000..c6b8889cf4c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/nls/Messages.java @@ -0,0 +1,156 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.nls; + +import java.lang.reflect.Field; + +import org.eclipse.osgi.util.NLS; + +/** + * Terminal plug-in externalized strings management. + */ +public class Messages extends NLS { + + // The plug-in resource bundle name + private static final String BUNDLE_NAME = "org.eclipse.tm.terminal.view.ui.nls.Messages"; //$NON-NLS-1$ + + /** + * Static constructor. + */ + static { + // Load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + + /** + * Returns the corresponding string for the given externalized strings + * key or null if the key does not exist. + * + * @param key The externalized strings key or null. + * @return The corresponding string or null. + */ + public static String getString(String key) { + if (key != null) { + try { + Field field = Messages.class.getDeclaredField(key); + return (String)field.get(null); + } catch (Exception e) { /* ignored on purpose */ } + } + + return null; + } + + // **** Declare externalized string id's down here ***** + + public static String Extension_error_missingRequiredAttribute; + public static String Extension_error_duplicateExtension; + public static String Extension_error_invalidExtensionPoint; + + public static String AbstractTriggerCommandHandler_error_executionFailed; + + public static String AbstractAction_error_commandExecutionFailed; + + public static String AbstractConfigurationPanel_delete; + public static String AbstractConfigurationPanel_deleteButtonTooltip; + public static String AbstractConfigurationPanel_hosts; + public static String AbstractConfigurationPanel_encoding; + public static String AbstractConfigurationPanel_encoding_custom; + public static String AbstractConfigurationPanel_encoding_custom_title; + public static String AbstractConfigurationPanel_encoding_custom_message; + public static String AbstractConfigurationPanel_encoding_custom_error; + + public static String TabTerminalListener_consoleClosed; + public static String TabTerminalListener_consoleConnecting; + + public static String NewTerminalViewAction_menu; + public static String NewTerminalViewAction_tooltip; + + public static String ToggleCommandFieldAction_menu; + public static String ToggleCommandFieldAction_toolTip; + + public static String SelectEncodingAction_menu; + public static String SelectEncodingAction_tooltip; + + public static String ProcessSettingsPage_dialogTitle; + public static String ProcessSettingsPage_processImagePathSelectorControl_label; + public static String ProcessSettingsPage_processImagePathSelectorControl_button; + public static String ProcessSettingsPage_processArgumentsControl_label; + public static String ProcessSettingsPage_processWorkingDirControl_label; + public static String ProcessSettingsPage_localEchoSelectorControl_label; + + public static String OutputStreamMonitor_error_readingFromStream; + + public static String InputStreamMonitor_error_writingToStream; + + public static String TerminalService_error_cannotCreateConnector; + public static String TerminalService_defaultTitle; + + public static String LaunchTerminalSettingsDialog_title; + public static String LaunchTerminalSettingsDialog_combo_label; + public static String LaunchTerminalSettingsDialog_group_label; + + public static String TabScrollLockAction_text; + public static String TabScrollLockAction_tooltip; + + public static String LaunchTerminalSettingsDialog_error_title; + public static String LaunchTerminalSettingsDialog_error_invalidSettings; + public static String LaunchTerminalSettingsDialog_error_unknownReason; + + public static String EncodingSelectionDialog_title; + + public static String TabFolderManager_encoding; + public static String TabFolderManager_state_connected; + public static String TabFolderManager_state_connecting; + public static String TabFolderManager_state_closed; + + public static String NoteCompositeHelper_note_label; + + // showin messages + + public static String ProcessConnector_error_creatingProcess; + + public static String PreferencePage_label; + public static String PreferencePage_executables_label; + public static String PreferencePage_executables_column_name_label; + public static String PreferencePage_executables_column_path_label; + public static String PreferencePage_executables_button_add_label; + public static String PreferencePage_executables_button_edit_label; + public static String PreferencePage_executables_button_remove_label; + public static String PreferencePage_workingDir_label; + public static String PreferencePage_workingDir_userhome_label; + public static String PreferencePage_workingDir_eclipsehome_label; + public static String PreferencePage_workingDir_eclipsews_label; + public static String PreferencePage_workingDir_button_browse; + public static String PreferencePage_workingDir_note_label; + public static String PreferencePage_workingDir_note_text; + public static String PreferencePage_workingDir_button_variables; + public static String PreferencePage_workingDir_invalid; + public static String PreferencePage_command_label; + public static String PreferencePage_command_button_browse; + public static String PreferencePage_command_invalid; + public static String PreferencePage_command_note_label; + public static String PreferencePage_command_note_text; + public static String PreferencePage_command_arguments_label; + + public static String ExternalExecutablesDialog_title_add; + public static String ExternalExecutablesDialog_title_edit; + public static String ExternalExecutablesDialog_button_add; + public static String ExternalExecutablesDialog_button_browse; + public static String ExternalExecutablesDialog_field_path; + public static String ExternalExecutablesDialog_field_name; + public static String ExternalExecutablesDialog_field_args; + public static String ExternalExecutablesDialog_field_icon; + public static String ExternalExecutablesDialog_field_translate; + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/nls/Messages.properties b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/nls/Messages.properties new file mode 100644 index 00000000000..45a8ea7bedf --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/nls/Messages.properties @@ -0,0 +1,115 @@ +############################################################################### +# Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is +# available at https://www.eclipse.org/legal/epl-2.0/ +# +# SPDX-License-Identifier: EPL-2.0 +# +# Contributors: +# Wind River Systems - initial API and implementation +############################################################################### + +Extension_error_missingRequiredAttribute=Required attribute "{0}" missing for extension "{1}"! +Extension_error_duplicateExtension=Duplicate extension with id ''{0}''. Ignoring duplicated contribution from contributor ''{1}''! +Extension_error_invalidExtensionPoint=Failed to instantiate the executable extension from extension point ''{0}''. + +AbstractTriggerCommandHandler_error_executionFailed=Failed to execute command {0}. + +AbstractAction_error_commandExecutionFailed="Failed to execute command (id = {0}). Possibly caused by: {1} + +AbstractConfigurationPanel_delete=Delete +AbstractConfigurationPanel_deleteButtonTooltip=Delete terminal settings for host +AbstractConfigurationPanel_hosts=Hosts: +AbstractConfigurationPanel_encoding=Encoding: +AbstractConfigurationPanel_encoding_custom=Other... +AbstractConfigurationPanel_encoding_custom_title=Other... +AbstractConfigurationPanel_encoding_custom_message=Please enter the name of the encoding to use for the terminal. +AbstractConfigurationPanel_encoding_custom_error=Unsupported encoding. Please enter the name of a supported encoding. + +TabTerminalListener_consoleClosed=<{1}> {0} +TabTerminalListener_consoleConnecting={0} : {1}... + +NewTerminalViewAction_menu=New Terminal View +NewTerminalViewAction_tooltip=Open a new Terminal View + +ToggleCommandFieldAction_menu=Toggle Command Input Field +ToggleCommandFieldAction_toolTip=Toggle Command Input Field + +SelectEncodingAction_menu=Switch Encoding... +SelectEncodingAction_tooltip=Switch the Encoding of the active Terminal + +ProcessSettingsPage_dialogTitle=Select Process Image +ProcessSettingsPage_processImagePathSelectorControl_label=Image Path: +ProcessSettingsPage_processImagePathSelectorControl_button=Browse +ProcessSettingsPage_processArgumentsControl_label=Arguments: +ProcessSettingsPage_processWorkingDirControl_label=Working Dir: +ProcessSettingsPage_localEchoSelectorControl_label=Local Echo + +OutputStreamMonitor_error_readingFromStream=Exception when reading from stream. Possibly caused by: {0} + +InputStreamMonitor_error_writingToStream=Exception when writing to stream. Possibly caused by: {0} + +TerminalService_error_cannotCreateConnector=Cannot create a valid terminal connector instance from the provided terminal properties. +TerminalService_defaultTitle=Console + +LaunchTerminalSettingsDialog_title=Launch Terminal +LaunchTerminalSettingsDialog_combo_label=Choose terminal: +LaunchTerminalSettingsDialog_group_label=Settings + +TabScrollLockAction_text=Scroll &Lock +TabScrollLockAction_tooltip=Scroll Lock + +LaunchTerminalSettingsDialog_error_title=Terminal Settings +LaunchTerminalSettingsDialog_error_invalidSettings=The specified settings are invalid\n\n\ +{0}\n\n\ +Please review and specify valid settings. Or cancel the settings dialog to abort. +LaunchTerminalSettingsDialog_error_unknownReason=Cannot determine specifically which setting is invalid. + +EncodingSelectionDialog_title=Encoding + +TabFolderManager_encoding=Encoding: {0} +TabFolderManager_state_connected=Connected +TabFolderManager_state_connecting=Connecting +TabFolderManager_state_closed=Closed + +NoteCompositeHelper_note_label=Note: + +# ----- showin + +ProcessConnector_error_creatingProcess=Exception when creating process. Possibly caused by: {0} + +ExternalExecutablesDialog_title_add=Add External Executable +ExternalExecutablesDialog_title_edit=Edit External Executable +ExternalExecutablesDialog_button_add=Add +ExternalExecutablesDialog_button_browse=Browse... +ExternalExecutablesDialog_field_path=Path: +ExternalExecutablesDialog_field_name=Name: +ExternalExecutablesDialog_field_args=Arguments: +ExternalExecutablesDialog_field_icon=Icon: +ExternalExecutablesDialog_field_translate=Translate Backslashes on Paste + +# ----- Preference Pages ----- + +PreferencePage_label=Local Terminal Settings: +PreferencePage_executables_label="Show In ..." Custom Entries +PreferencePage_executables_column_name_label=Name +PreferencePage_executables_column_path_label=Path +PreferencePage_executables_button_add_label=Add... +PreferencePage_executables_button_edit_label=Edit... +PreferencePage_executables_button_remove_label=Remove +PreferencePage_workingDir_label=Initial Working Directory +PreferencePage_workingDir_userhome_label=User home +PreferencePage_workingDir_eclipsehome_label=Eclipse home +PreferencePage_workingDir_eclipsews_label=Eclipse workspace +PreferencePage_workingDir_button_browse=&Browse... +PreferencePage_workingDir_note_label=Note: +PreferencePage_workingDir_note_text=The chosen initial working directory might be overwritten by the current selection of the active view. +PreferencePage_workingDir_button_variables=&Variables... +PreferencePage_workingDir_invalid=Selected initial working directory is not a directory or is not readable. +PreferencePage_command_label=Shell Command +PreferencePage_command_button_browse=&Browse... +PreferencePage_command_invalid=Selected shell command is not a file or is not readable or executable. +PreferencePage_command_note_label=Note: +PreferencePage_command_note_text=Leave the shell command empty to fallback to the SHELL environment variable or if not set, to /bin/sh. +PreferencePage_command_arguments_label=Arguments: diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/panels/AbstractConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/panels/AbstractConfigurationPanel.java new file mode 100644 index 00000000000..069fd3415c9 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/panels/AbstractConfigurationPanel.java @@ -0,0 +1,204 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.panels; + +import java.util.Map; + +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IMessageProvider; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; + +/** + * Abstract terminal launcher configuration panel implementation. + */ +public abstract class AbstractConfigurationPanel implements IConfigurationPanel { + private final IConfigurationPanelContainer container; + + private Composite topControl = null; + + // The selection + private ISelection selection; + + private String message = null; + private int messageType = IMessageProvider.NONE; + + private boolean enabled = true; + + /** + * Constructor. + * + * @param container The configuration panel container or null. + */ + public AbstractConfigurationPanel(IConfigurationPanelContainer container) { + super(); + this.container = container; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#getContainer() + */ + @Override + public IConfigurationPanelContainer getContainer() { + return container; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessage() + */ + @Override + public final String getMessage() { + return message; + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.IMessageProvider#getMessageType() + */ + @Override + public final int getMessageType() { + return messageType; + } + + /** + * Set the message and the message type to display. + * + * @param message The message or null. + * @param messageType The message type or IMessageProvider.NONE. + */ + protected final void setMessage(String message, int messageType) { + this.message = message; + this.messageType = messageType; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#dispose() + */ + @Override + public void dispose() { + } + + /** + * Sets the top control. + * + * @param topControl The top control or null. + */ + protected void setControl(Composite topControl) { + this.topControl = topControl; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#getControl() + */ + @Override + public Composite getControl() { + return topControl; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setSelection(org.eclipse.jface.viewers.ISelection) + */ + @Override + public void setSelection(ISelection selection) { + this.selection = selection; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#getSelection() + */ + @Override + public ISelection getSelection() { + return selection; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#doRestoreWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doRestoreWidgetValues(IDialogSettings settings, String idPrefix) { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#doSaveWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + } + + /** + * Returns the correctly prefixed dialog settings slot id. In case the given id + * suffix is null or empty, id is returned as is. + * + * @param settingsSlotId The dialog settings slot id to prefix. + * @param prefix The prefix. + * @return The correctly prefixed dialog settings slot id. + */ + public final String prefixDialogSettingsSlotId(String settingsSlotId, String prefix) { + if (settingsSlotId != null && prefix != null && prefix.trim().length() > 0) { + settingsSlotId = prefix + "." + settingsSlotId; //$NON-NLS-1$ + } + return settingsSlotId; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setEnabled(boolean) + */ + @Override + public void setEnabled(boolean enabled) { + this.enabled = enabled; + } + + /** + * @return Returns the enabled state. + */ + public boolean isEnabled() { + return enabled; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#isValid() + */ + @Override + public boolean isValid() { + setMessage(null, NONE); + return true; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#activate() + */ + @Override + public void activate() { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#extractData(java.util.Map) + */ + @Override + public void extractData(Map data) { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#setupData(java.util.Map) + */ + @Override + public void setupData(Map data) { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel#updateData(java.util.Map) + */ + @Override + public void updateData(Map data) { + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/panels/AbstractExtendedConfigurationPanel.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/panels/AbstractExtendedConfigurationPanel.java new file mode 100644 index 00000000000..e58140f5444 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/panels/AbstractExtendedConfigurationPanel.java @@ -0,0 +1,635 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.panels; + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Platform; +import org.eclipse.jface.dialogs.IDialogSettings; +import org.eclipse.jface.dialogs.IInputValidator; +import org.eclipse.jface.dialogs.InputDialog; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Label; +import org.eclipse.tm.terminal.view.core.TerminalContextPropertiesProviderFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalContextPropertiesProvider; +import org.eclipse.tm.terminal.view.core.interfaces.constants.IContextPropertiesConstants; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.ISharedImages; +import org.eclipse.ui.WorkbenchEncoding; +import org.osgi.framework.Bundle; + +/** + * Abstract terminal configuration panel implementation. + */ +public abstract class AbstractExtendedConfigurationPanel extends AbstractConfigurationPanel { + private static final String LAST_HOST_TAG = "lastHost";//$NON-NLS-1$ + private static final String HOSTS_TAG = "hosts";//$NON-NLS-1$ + private static final String ENCODINGS_TAG = "encodings"; //$NON-NLS-1$ + + // The sub-controls + /* default */ Combo hostCombo; + private Button deleteHostButton; + /* default */ Combo encodingCombo; + + // The last selected encoding + /* default */ String lastSelectedEncoding; + // The last entered custom encodings + /* default */ final List encodingHistory = new ArrayList(); + + // A map containing the settings per host + protected final Map> hostSettingsMap = new HashMap>(); + + /** + * Constructor. + * + * @param container The configuration panel container or null. + */ + public AbstractExtendedConfigurationPanel(IConfigurationPanelContainer container) { + super(container); + } + + /** + * Returns the host name or IP from the current selection. + * + * @return The host name or IP, or null. + */ + public String getSelectionHost() { + ISelection selection = getSelection(); + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + ITerminalContextPropertiesProvider provider = TerminalContextPropertiesProviderFactory.getProvider(element); + if (provider != null) { + Map props = provider.getTargetAddress(element); + if (props != null && props.containsKey(IContextPropertiesConstants.PROP_ADDRESS)) { + return props.get(IContextPropertiesConstants.PROP_ADDRESS); + } + } + } + + return null; + } + + /** + * Returns the default encoding based on the current selection. + * + * @return The default encoding or null. + */ + public String getSelectionEncoding() { + ISelection selection = getSelection(); + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + Object element = ((IStructuredSelection) selection).getFirstElement(); + ITerminalContextPropertiesProvider provider = TerminalContextPropertiesProviderFactory.getProvider(element); + if (provider != null) { + Object encoding = provider.getProperty(element, IContextPropertiesConstants.PROP_DEFAULT_ENCODING); + if (encoding instanceof String) return ((String) encoding).trim(); + } + } + + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#doRestoreWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doRestoreWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + String[] hosts = settings.getArray(HOSTS_TAG); + if (hosts != null) { + for (String hostEntry : hosts) { + String[] hostString = hostEntry.split("\\|");//$NON-NLS-1$ + String hostName = hostString[0]; + if (hostString.length == 2) { + HashMap attr = deSerialize(hostString[1]); + hostSettingsMap.put(hostName, attr); + } + else { + hostSettingsMap.put(hostName, new HashMap()); + } + } + } + + if (!isWithoutSelection()) { + String host = getSelectionHost(); + if (host != null) { + fillSettingsForHost(host); + } + } + else { + if (hostCombo != null) { + fillHostCombo(); + String lastHost = settings.get(LAST_HOST_TAG); + if (lastHost != null) { + int index = hostCombo.indexOf(lastHost); + if (index != -1) { + hostCombo.select(index); + } + else { + hostCombo.select(0); + } + } + else { + hostCombo.select(0); + } + fillSettingsForHost(hostCombo.getText()); + } + } + + encodingHistory.clear(); + String[] encodings = settings.getArray(ENCODINGS_TAG); + if (encodings != null && encodings.length > 0) { + encodingHistory.addAll(Arrays.asList(encodings)); + for (String encoding : encodingHistory) { + encodingCombo.add(encoding, encodingCombo.getItemCount() - 1); + } + } + } + + /** + * Restore the encodings widget values. + * + * @param settings The dialog settings. Must not be null. + * @param idPrefix The prefix or null. + */ + protected void doRestoreEncodingsWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + String encoding = settings.get(prefixDialogSettingsSlotId(ITerminalsConnectorConstants.PROP_ENCODING, idPrefix)); + if (encoding != null && encoding.trim().length() > 0) { + setEncoding(encoding); + } + } + + /** + * Decode the host settings from the given string. + * + * @param hostString The encoded host settings. Must not be null. + * @return The decoded host settings. + */ + private HashMap deSerialize(String hostString) { + Assert.isNotNull(hostString); + HashMap attr = new HashMap(); + + if (hostString.length() != 0) { + String[] hostAttrs = hostString.split("\\:");//$NON-NLS-1$ + for (int j = 0; j < hostAttrs.length-1; j = j + 2) { + String key = hostAttrs[j]; + String value = hostAttrs[j + 1]; + attr.put(key, value); + } + } + return attr; + } + + /** + * Encode the host settings to a string. + * + * @param hostEntry The host settings. Must not be null. + * @param hostString The host string to encode to. Must not be null. + */ + private void serialize(Map hostEntry, StringBuilder hostString) { + Assert.isNotNull(hostEntry); + Assert.isNotNull(hostString); + + if (hostEntry.keySet().size() != 0) { + Iterator> nextHostAttr = hostEntry.entrySet().iterator(); + while (nextHostAttr.hasNext()) { + Entry entry = nextHostAttr.next(); + String attrKey = entry.getKey(); + String attrValue = entry.getValue(); + hostString.append(attrKey + ":" + attrValue + ":");//$NON-NLS-1$ //$NON-NLS-2$ + } + hostString.deleteCharAt(hostString.length() - 1); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.panels.AbstractConfigurationPanel#doSaveWidgetValues(org.eclipse.jface.dialogs.IDialogSettings, java.lang.String) + */ + @Override + public void doSaveWidgetValues(IDialogSettings settings, String idPrefix) { + Iterator nextHost = hostSettingsMap.keySet().iterator(); + String[] hosts = new String[hostSettingsMap.keySet().size()]; + int i = 0; + while (nextHost.hasNext()) { + StringBuilder hostString = new StringBuilder(); + String host = nextHost.next(); + hostString.append(host + "|");//$NON-NLS-1$ + Map hostEntry = hostSettingsMap.get(host); + serialize(hostEntry, hostString); + hosts[i] = hostString.toString(); + i = i + 1; + } + settings.put(HOSTS_TAG, hosts); + if (isWithoutSelection()) { + if (hostCombo != null) { + String host = getHostFromSettings(); + if (host != null) settings.put(LAST_HOST_TAG, host); + } + } + + if (!encodingHistory.isEmpty()) { + settings.put(ENCODINGS_TAG, encodingHistory.toArray(new String[encodingHistory.size()])); + } + } + + /** + * Save the encodings widget values. + * + * @param settings The dialog settings. Must not be null. + * @param idPrefix The prefix or null. + */ + protected void doSaveEncodingsWidgetValues(IDialogSettings settings, String idPrefix) { + Assert.isNotNull(settings); + + String encoding = getEncoding(); + if (encoding != null) { + settings.put(prefixDialogSettingsSlotId(ITerminalsConnectorConstants.PROP_ENCODING, idPrefix), encoding); + } + } + + protected abstract void saveSettingsForHost(boolean add); + + protected abstract void fillSettingsForHost(String host); + + protected abstract String getHostFromSettings(); + + protected void removeSecurePassword(String host) { + // noop by default + } + + /** + * Returns the selected host from the hosts combo widget. + * + * @return The selected host or null. + */ + protected final String getHostFromCombo() { + return hostCombo != null && !hostCombo.isDisposed() ? hostCombo.getText() : null; + } + + protected void removeSettingsForHost(String host) { + if (hostSettingsMap.containsKey(host)) { + hostSettingsMap.remove(host); + } + } + + /** + * Returns the list of host names of the persisted hosts. + * + * @return The list of host names. + */ + private List getHostList() { + List hostList = new ArrayList(); + hostList.addAll(hostSettingsMap.keySet()); + return hostList; + } + + /** + * Fill the host combo with the stored per host setting names. + */ + protected void fillHostCombo() { + if (hostCombo != null) { + hostCombo.removeAll(); + List hostList = getHostList(); + Collections.sort(hostList); + Iterator nextHost = hostList.iterator(); + while (nextHost.hasNext()) { + String host = nextHost.next(); + hostCombo.add(host); + } + if (hostList.size() <= 1) { + hostCombo.setEnabled(false); + } + else { + hostCombo.setEnabled(true); + + } + if (deleteHostButton != null) { + if (hostList.size() == 0) { + deleteHostButton.setEnabled(false); + } + else { + deleteHostButton.setEnabled(true); + } + } + } + } + + public boolean isWithoutSelection() { + ISelection selection = getSelection(); + if (selection == null) { + return true; + } + if (selection instanceof IStructuredSelection && selection.isEmpty()) { + return true; + } + return false; + } + + public boolean isWithHostList() { + return true; + } + + /** + * Create the host selection combo. + * + * @param parent The parent composite. Must not be null. + * @param separator If true, a separator will be added after the controls. + */ + protected void createHostsUI(Composite parent, boolean separator) { + Assert.isNotNull(parent); + + if (isWithoutSelection() && isWithHostList()) { + Composite comboComposite = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(3, false); + layout.marginHeight = 0; + layout.marginWidth = 0; + comboComposite.setLayout(layout); + comboComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + Label label = new Label(comboComposite, SWT.HORIZONTAL); + label.setText(Messages.AbstractConfigurationPanel_hosts); + + hostCombo = new Combo(comboComposite, SWT.READ_ONLY); + hostCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + hostCombo.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String host = hostCombo.getText(); + fillSettingsForHost(host); + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + }); + + deleteHostButton = new Button(comboComposite, SWT.NONE); + // deleteHostButton.setText(Messages.AbstractConfigurationPanel_delete); + + ISharedImages workbenchImages = UIPlugin.getDefault().getWorkbench().getSharedImages(); + deleteHostButton.setImage(workbenchImages.getImageDescriptor(ISharedImages.IMG_TOOL_DELETE).createImage()); + + deleteHostButton.setToolTipText(Messages.AbstractConfigurationPanel_deleteButtonTooltip); + deleteHostButton.addSelectionListener(new SelectionListener() { + + @Override + public void widgetSelected(SelectionEvent e) { + String host = getHostFromCombo(); + if (host != null && host.length() != 0) { + removeSettingsForHost(host); + removeSecurePassword(host); + fillHostCombo(); + hostCombo.select(0); + host = getHostFromCombo(); + if (host != null && host.length() != 0) { + fillSettingsForHost(host); + } + } + } + + @Override + public void widgetDefaultSelected(SelectionEvent e) { + widgetSelected(e); + } + }); + + if (separator) { + Label sep = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + } + } + } + + /** + * Create the encoding selection combo. + * + * @param parent The parent composite. Must not be null. + * @param separator If true, a separator will be added before the controls. + */ + protected void createEncodingUI(final Composite parent, boolean separator) { + Assert.isNotNull(parent); + + if (separator) { + Label sep = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL); + sep.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + } + + Composite panel = new Composite(parent, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + panel.setLayout(layout); + panel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + Label label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.AbstractConfigurationPanel_encoding); + + encodingCombo = new Combo(panel, SWT.READ_ONLY); + encodingCombo.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + encodingCombo.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + if (Messages.AbstractConfigurationPanel_encoding_custom.equals(encodingCombo.getText())) { + InputDialog dialog = new InputDialog(parent.getShell(), + Messages.AbstractConfigurationPanel_encoding_custom_title, + Messages.AbstractConfigurationPanel_encoding_custom_message, + null, + new IInputValidator() { + @Override + public String isValid(String newText) { + boolean valid = false; + try { + if (newText != null && !"".equals(newText)) { //$NON-NLS-1$ + valid = Charset.isSupported(newText); + } + } catch (IllegalCharsetNameException e) { /* ignored on purpose */ } + + if (!valid) { + return newText != null && !"".equals(newText) ? Messages.AbstractConfigurationPanel_encoding_custom_error : ""; //$NON-NLS-1$ //$NON-NLS-2$ + } + return null; + } + }); + if (dialog.open() == Window.OK) { + String encoding = dialog.getValue(); + encodingCombo.add(encoding, encodingCombo.getItemCount() - 1); + encodingCombo.select(encodingCombo.indexOf(encoding)); + lastSelectedEncoding = encodingCombo.getText(); + + // Remember the last 5 custom encodings entered + if (!encodingHistory.contains(encoding)) { + if (encodingHistory.size() == 5) encodingHistory.remove(4); + encodingHistory.add(encoding); + } + + } else { + encodingCombo.select(encodingCombo.indexOf(lastSelectedEncoding)); + } + } + } + }); + + fillEncodingCombo(); + + // Apply any default encoding derived from the current selection + String defaultEncoding = getSelectionEncoding(); + if (defaultEncoding != null && !"".equals(defaultEncoding)) { //$NON-NLS-1$ + setEncoding(defaultEncoding); + } + } + + /** + * Fill the encoding combo. + */ + protected void fillEncodingCombo() { + if (encodingCombo != null) { + List encodings = new ArrayList(); + + // Default encoding + encodings.add("Default (ISO-8859-1)"); //$NON-NLS-1$ + + // The currently selected IDE encoding from the preferences + String ideEncoding = getResourceEncoding(); + + // The default Eclipse Workbench encoding (configured in the preferences) + String eclipseEncoding = WorkbenchEncoding.getWorkbenchDefaultEncoding(); + + // The default host (Java VM) encoding + String hostEncoding = Charset.defaultCharset().name(); + + addEncodings(encodings, "UTF-8", ideEncoding, eclipseEncoding, hostEncoding); //$NON-NLS-1$ + + // The "Other..." encoding + encodings.add(Messages.AbstractConfigurationPanel_encoding_custom); + + encodingCombo.setItems(encodings.toArray(new String[encodings.size()])); + encodingCombo.select(0); + + lastSelectedEncoding = encodingCombo.getText(); + } + } + + /** + * Add given encoding names to the list. Duplicates are filtered out by comparing aliases. + */ + private void addEncodings(List encodings, String... toadd) { + Set aliases = new HashSet(); + for (String name : toadd) { + if (name == null) + continue; + try { + Charset cs = Charset.forName(name); + if (aliases.containsAll(cs.aliases())) + continue; + if (aliases.contains(name.toLowerCase())) + continue; + aliases.addAll(cs.aliases()); + aliases.add(name.toLowerCase()); + encodings.add(name); + } catch (Exception e) { + // skip + } + } + } + + /** + * Get the current value of the encoding preference. If the value is not set + * return null. + *

              + * Note: Copied from org.eclipse.ui.ide.IDEEncoding. + * + * @return String + */ + @SuppressWarnings("deprecation") + private String getResourceEncoding() { + String preference = null; + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + preference = org.eclipse.core.resources.ResourcesPlugin.getPlugin().getPluginPreferences().getString(org.eclipse.core.resources.ResourcesPlugin.PREF_ENCODING); + } + + return preference != null && preference.length() > 0 ? preference : null; + } + + /** + * Select the encoding. + * + * @param encoding The encoding. Must not be null. + */ + protected void setEncoding(String encoding) { + Assert.isNotNull(encoding); + + if (encodingCombo != null && !encodingCombo.isDisposed()) { + int index = encodingCombo.indexOf("ISO-8859-1".equals(encoding) ? "Default (ISO-8859-1)" : encoding); //$NON-NLS-1$ //$NON-NLS-2$ + if (index != -1) encodingCombo.select(index); + else { + encodingCombo.add(encoding, encodingCombo.getItemCount() - 1); + encodingCombo.select(encodingCombo.indexOf(encoding)); + } + + lastSelectedEncoding = encodingCombo.getText(); + } + } + + /** + * Returns the selected encoding. + * + * @return The selected encoding or null. + */ + protected String getEncoding() { + String encoding = encodingCombo != null && !encodingCombo.isDisposed() ? encodingCombo.getText() : null; + return encoding != null && encoding.startsWith("Default") ? null : encoding; //$NON-NLS-1$ + } + + /** + * Returns if or if not the selected encoding is supported. + * + * @return True if the selected encoding is supported. + */ + protected boolean isEncodingValid() { + try { + String encoding = getEncoding(); + return Charset.isSupported(encoding != null ? encoding : "ISO-8859-1"); //$NON-NLS-1$ + } catch (IllegalCharsetNameException e) { + return false; + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/preferences/PreferencePage.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/preferences/PreferencePage.java new file mode 100644 index 00000000000..08e56d9245d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/preferences/PreferencePage.java @@ -0,0 +1,680 @@ +/******************************************************************************* + * Copyright (c) 2014, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.preferences; + +import java.io.File; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Path; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.URIUtil; +import org.eclipse.core.variables.IStringVariableManager; +import org.eclipse.core.variables.VariablesPlugin; +import org.eclipse.jface.dialogs.Dialog; +import org.eclipse.jface.resource.ImageDescriptor; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; +import org.eclipse.jface.viewers.ColumnWeightData; +import org.eclipse.jface.viewers.ILabelProviderListener; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.IStructuredContentProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.ITableLabelProvider; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.TableLayout; +import org.eclipse.jface.viewers.TableViewer; +import org.eclipse.jface.viewers.Viewer; +import org.eclipse.jface.window.Window; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.graphics.ImageData; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Button; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.DirectoryDialog; +import org.eclipse.swt.widgets.FileDialog; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Table; +import org.eclipse.swt.widgets.TableColumn; +import org.eclipse.swt.widgets.Text; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.controls.NoteCompositeHelper; +import org.eclipse.tm.terminal.view.ui.interfaces.IExternalExecutablesProperties; +import org.eclipse.tm.terminal.view.ui.interfaces.IPreferenceKeys; +import org.eclipse.tm.terminal.view.ui.local.showin.ExternalExecutablesDialog; +import org.eclipse.tm.terminal.view.ui.local.showin.ExternalExecutablesManager; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.osgi.framework.Bundle; + +/** + * Terminal top preference page implementation. + */ +public class PreferencePage extends org.eclipse.jface.preference.PreferencePage implements IWorkbenchPreferencePage { + /* default */ TableViewer viewer; + private Button addButton; + private Button editButton; + private Button removeButton; + /* default */ Combo workingDir; + private Button browseButton; + + private Button variablesButton; + private boolean hasVariablesButton = false; + + /* default */ Text command; + private Button commandBrowseButton; + private Text arguments; + + /* default */ final List> executables = new ArrayList>(); + /* default */ final Map images = new HashMap(); + + /* default */ static final Object[] NO_ELEMENTS = new Object[0]; + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + @Override + public void init(IWorkbench workbench) { + Bundle bundle = Platform.getBundle("org.eclipse.debug.ui"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + hasVariablesButton = true; + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite) + */ + @Override + protected Control createContents(final Composite parent) { + final GC gc = new GC(parent); + gc.setFont(JFaceResources.getDialogFont()); + + Composite panel = new Composite(parent, SWT.NONE); + panel.setLayout(new GridLayout()); + GridData layoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false); + panel.setLayoutData(layoutData); + + Label label = new Label(panel, SWT.HORIZONTAL); + label.setText(Messages.PreferencePage_label); + label.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + if (!Platform.OS_WIN32.equals(Platform.getOS())) { + Group group = new Group(panel, SWT.NONE); + group.setText(Messages.PreferencePage_command_label); + group.setLayout(new GridLayout(2, false)); + group.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + + command = new Text(group, SWT.SINGLE | SWT.BORDER); + command.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + command.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + boolean valid = true; + String message = null; + + String text = command.getText(); + if (text != null && !"".equals(text.trim())) { //$NON-NLS-1$ + IPath p = new Path(text.trim()); + valid = p.toFile().isFile() && p.toFile().canRead() && p.toFile().canExecute(); + if (!valid) message = Messages.PreferencePage_command_invalid; + } + + setValid(valid); + setErrorMessage(message); + } + }); + + commandBrowseButton = new Button(group, SWT.PUSH); + commandBrowseButton.setText(Messages.PreferencePage_command_button_browse); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 14); + commandBrowseButton.setLayoutData(layoutData); + commandBrowseButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + FileDialog dialog = new FileDialog(parent.getShell(), SWT.OPEN); + + String text = command.getText(); + if (text != null && !"".equals(text.trim())) { //$NON-NLS-1$ + IPath p = new Path(text); + + if (p.toFile().isFile() || !p.toFile().exists()) { + dialog.setFilterPath(p.removeLastSegments(1).toOSString()); + dialog.setFileName(p.lastSegment()); + } else if (p.toFile().isDirectory()) { + dialog.setFilterPath(p.toOSString()); + } + } + + String selected = dialog.open(); + if (selected != null) { + IPath sp = new Path(selected); + command.setText(sp.toOSString()); + } + } + }); + + String cmd = UIPlugin.getScopedPreferences().getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX); + if (cmd != null && !"".equals(cmd)) { //$NON-NLS-1$ + command.setText(new Path(cmd).toOSString()); + } + + Composite argsPanel = new Composite(group, SWT.NONE); + GridLayout layout = new GridLayout(2, false); + layout.marginHeight = 0; layout.marginWidth = 0; + argsPanel.setLayout(layout); + layoutData = new GridData(SWT.FILL, SWT.BEGINNING, true, false); + layoutData.horizontalSpan = 2; + argsPanel.setLayoutData(layoutData); + + label = new Label(argsPanel, SWT.NONE); + label.setText(Messages.PreferencePage_command_arguments_label); + + arguments = new Text(argsPanel, SWT.SINGLE | SWT.BORDER); + arguments.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + + String args = UIPlugin.getScopedPreferences().getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX_ARGS); + if (args != null && !"".equals(args)) { //$NON-NLS-1$ + arguments.setText(args); + } + + NoteCompositeHelper.createNoteComposite(group.getFont(), group, Messages.PreferencePage_command_note_label, Messages.PreferencePage_command_note_text); + } + + Group group = new Group(panel, SWT.NONE); + group.setText(Messages.PreferencePage_workingDir_label); + group.setLayout(new GridLayout(hasVariablesButton ? 3 : 2, false)); + group.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + + workingDir = new Combo(group, SWT.DROP_DOWN); + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + workingDir.setItems(new String[] { Messages.PreferencePage_workingDir_userhome_label, Messages.PreferencePage_workingDir_eclipsehome_label, Messages.PreferencePage_workingDir_eclipsews_label }); + } else { + workingDir.setItems(new String[] { Messages.PreferencePage_workingDir_userhome_label, Messages.PreferencePage_workingDir_eclipsehome_label }); + } + workingDir.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); + workingDir.select(0); + workingDir.addModifyListener(new ModifyListener() { + @Override + public void modifyText(ModifyEvent e) { + boolean valid = true; + String message = null; + + String text = workingDir.getText(); + if (text != null && !"".equals(text.trim()) //$NON-NLS-1$ + && !Messages.PreferencePage_workingDir_userhome_label.equals(text) + && !Messages.PreferencePage_workingDir_eclipsehome_label.equals(text) + && !Messages.PreferencePage_workingDir_eclipsews_label.equals(text)) { + try { + // Resolve possible dynamic variables + IStringVariableManager vm = VariablesPlugin.getDefault().getStringVariableManager(); + String resolved = vm.performStringSubstitution(text.trim()); + + IPath p = new Path(resolved); + valid = p.toFile().canRead() && p.toFile().isDirectory(); + if (!valid) message = Messages.PreferencePage_workingDir_invalid; + } catch (CoreException ex) { + valid = false; + message = ex.getLocalizedMessage(); + } + } + + setValid(valid); + setErrorMessage(message); + } + }); + + browseButton = new Button(group, SWT.PUSH); + browseButton.setText(Messages.PreferencePage_workingDir_button_browse); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 14); + browseButton.setLayoutData(layoutData); + browseButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + IPath uh = null; + IPath eh = null; + IPath ew = null; + + // HOME + String home = System.getProperty("user.home"); //$NON-NLS-1$ + if (home != null && !"".equals(home)) uh = new Path(home); //$NON-NLS-1$ + + // ECLIPSE_HOME + String eclipseHomeLocation = System.getProperty("eclipse.home.location"); //$NON-NLS-1$ + if (eclipseHomeLocation != null) { + try { + URI uri = URIUtil.fromString(eclipseHomeLocation); + File f = URIUtil.toFile(uri); + eh = new Path(f.getAbsolutePath()); + } catch (URISyntaxException ex) { /* ignored on purpose */ } + } + + // ECLIPSE_WORKSPACE + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + if (org.eclipse.core.resources.ResourcesPlugin.getWorkspace() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot() != null + && org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation() != null) { + ew = org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation(); + } + } + + DirectoryDialog dialog = new DirectoryDialog(parent.getShell(), SWT.OPEN); + + // Determine the filter path + String text = workingDir.getText(); + if (Messages.PreferencePage_workingDir_userhome_label.equals(text)) { + dialog.setFilterPath(uh.toOSString()); + } else if (Messages.PreferencePage_workingDir_eclipsehome_label.equals(text)) { + dialog.setFilterPath(eh.toOSString()); + } else if (Messages.PreferencePage_workingDir_eclipsews_label.equals(text)) { + dialog.setFilterPath(ew.toOSString()); + } else if (text != null && !"".equals(text.trim())) { //$NON-NLS-1$ + try { + // Resolve possible dynamic variables + IStringVariableManager vm = VariablesPlugin.getDefault().getStringVariableManager(); + String resolved = vm.performStringSubstitution(text.trim()); + dialog.setFilterPath(resolved); + } catch (CoreException ex) { + if (Platform.inDebugMode()) { + UIPlugin.getDefault().getLog().log(ex.getStatus()); + } + } + } + + String selected = dialog.open(); + if (selected != null) { + IPath sp = new Path(selected); + + if (uh.equals(sp)) { + workingDir.select(0); + } else if (eh.equals(sp)) { + workingDir.select(1); + } else if (ew.equals(sp)) { + workingDir.select(2); + } else { + workingDir.setText(sp.toOSString()); + } + } + } + }); + + if (hasVariablesButton) { + variablesButton = new Button(group, SWT.PUSH); + variablesButton.setText(Messages.PreferencePage_workingDir_button_variables); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 14); + variablesButton.setLayoutData(layoutData); + variablesButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + org.eclipse.debug.ui.StringVariableSelectionDialog dialog = new org.eclipse.debug.ui.StringVariableSelectionDialog(getShell()); + dialog.open(); + String expression = dialog.getVariableExpression(); + if (expression != null) { + if ("${eclipse_home}".equals(expression)) { //$NON-NLS-1$ + workingDir.select(1); + } else if ("${workspace_loc}".equals(expression)) { //$NON-NLS-1$ + workingDir.select(2); + } else { + workingDir.setText(expression); + } + } + } + }); + } + + String initialCwd = UIPlugin.getScopedPreferences().getString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD); + if (initialCwd == null || IPreferenceKeys.PREF_INITIAL_CWD_USER_HOME.equals(initialCwd) || "".equals(initialCwd.trim())) { //$NON-NLS-1$ + workingDir.select(0); + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_HOME.equals(initialCwd) || "${eclipse_home}".equals(initialCwd)) { //$NON-NLS-1$ + workingDir.select(1); + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_WS.equals(initialCwd) || "${workspace_loc}".equals(initialCwd)) { //$NON-NLS-1$ + workingDir.select(2); + } else { + workingDir.setText(new Path(initialCwd).toOSString()); + } + + NoteCompositeHelper.createNoteComposite(group.getFont(), group, Messages.PreferencePage_workingDir_note_label, Messages.PreferencePage_workingDir_note_text); + + group = new Group(panel, SWT.NONE); + group.setText(Messages.PreferencePage_executables_label); + group.setLayout(new GridLayout(2, false)); + group.setLayoutData(new GridData(SWT.FILL, SWT.BEGINNING, true, false)); + + viewer = new TableViewer(group, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER | SWT.FULL_SELECTION); + + Table table = viewer.getTable(); + table.setHeaderVisible(true); + table.setLinesVisible(true); + + TableColumn column = new TableColumn(table, SWT.LEFT); + column.setText(Messages.PreferencePage_executables_column_name_label); + column = new TableColumn(table, SWT.LEFT); + column.setText(Messages.PreferencePage_executables_column_path_label); + + ColumnViewerToolTipSupport.enableFor(viewer); + + TableLayout tableLayout = new TableLayout(); + tableLayout.addColumnData(new ColumnWeightData(35)); + tableLayout.addColumnData(new ColumnWeightData(65)); + table.setLayout(tableLayout); + + layoutData = new GridData(SWT.FILL, SWT.FILL, true, true); + layoutData.heightHint = Dialog.convertHeightInCharsToPixels(gc.getFontMetrics(), 10); + table.setLayoutData(layoutData); + + Composite buttonsPanel = new Composite(group, SWT.NONE); + GridLayout layout = new GridLayout(); + layout.marginHeight = 0; layout.marginWidth = 0; + buttonsPanel.setLayout(layout); + buttonsPanel.setLayoutData(new GridData(SWT.LEAD, SWT.BEGINNING, false, false)); + + addButton = new Button(buttonsPanel, SWT.PUSH); + addButton.setText(Messages.PreferencePage_executables_button_add_label); + layoutData = new GridData(SWT.FILL, SWT.CENTER, false, false); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 10); + addButton.setLayoutData(layoutData); + addButton.addSelectionListener(new SelectionAdapter() { + @Override + public void widgetSelected(SelectionEvent e) { + ExternalExecutablesDialog dialog = new ExternalExecutablesDialog(PreferencePage.this.getShell(), false); + if (dialog.open() == Window.OK) { + // Get the executable properties and add it to the the list + Map executableData = dialog.getExecutableData(); + if (executableData != null && !executables.contains(executableData)) { + executables.add(executableData); + viewer.refresh(); + } + } + } + }); + + editButton = new Button(buttonsPanel, SWT.PUSH); + editButton.setText(Messages.PreferencePage_executables_button_edit_label); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 10); + editButton.setLayoutData(layoutData); + editButton.addSelectionListener(new SelectionAdapter() { + @SuppressWarnings("unchecked") + @Override + public void widgetSelected(SelectionEvent e) { + ISelection s = viewer.getSelection(); + if (s instanceof IStructuredSelection && !s.isEmpty()) { + Object element = ((IStructuredSelection)s).getFirstElement(); + if (element instanceof Map) { + final Map m = (Map)element; + ExternalExecutablesDialog dialog = new ExternalExecutablesDialog(PreferencePage.this.getShell(), true); + dialog.setExecutableData(m); + if (dialog.open() == Window.OK) { + Map executableData = dialog.getExecutableData(); + if (executableData != null) { + m.clear(); + m.putAll(executableData); + viewer.refresh(); + } + } + } + } + } + }); + + removeButton = new Button(buttonsPanel, SWT.PUSH); + removeButton.setText(Messages.PreferencePage_executables_button_remove_label); + layoutData = new GridData(SWT.FILL, SWT.CENTER, true, false); + layoutData.widthHint = Dialog.convertWidthInCharsToPixels(gc.getFontMetrics(), 10); + removeButton.setLayoutData(layoutData); + removeButton.addSelectionListener(new SelectionAdapter() { + @SuppressWarnings("unchecked") + @Override + public void widgetSelected(SelectionEvent e) { + ISelection s = viewer.getSelection(); + if (s instanceof IStructuredSelection && !s.isEmpty()) { + Iterator iterator = ((IStructuredSelection)s).iterator(); + while (iterator.hasNext()) { + Object element = iterator.next(); + if (element instanceof Map) { + Map m = (Map)element; + executables.remove(m); + } + viewer.refresh(); + } + } + } + }); + + viewer.setContentProvider(new IStructuredContentProvider() { + @Override + public Object[] getElements(Object inputElement) { + if (inputElement instanceof List && !((List)inputElement).isEmpty()) { + return ((List)inputElement).toArray(); + } + return NO_ELEMENTS; + } + + @Override + public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + } + + @Override + public void dispose() { + } + }); + + viewer.setLabelProvider(new ITableLabelProvider() { + @SuppressWarnings("unchecked") + @Override + public String getColumnText(Object element, int columnIndex) { + if (element instanceof Map) { + Map m = (Map)element; + + switch (columnIndex) { + case 0: + return (String)m.get(IExternalExecutablesProperties.PROP_NAME); + case 1: + return (String)m.get(IExternalExecutablesProperties.PROP_PATH); + } + } + return null; + } + + @SuppressWarnings("unchecked") + @Override + public Image getColumnImage(Object element, int columnIndex) { + Image i = null; + + if (element instanceof Map) { + switch (columnIndex) { + case 0: + Map m = (Map)element; + String icon = (String) m.get(IExternalExecutablesProperties.PROP_ICON); + if (icon != null) { + i = images.get(icon); + if (i == null) { + ImageData id = ExternalExecutablesManager.loadImage(icon); + if (id != null) { + ImageDescriptor d = ImageDescriptor.createFromImageData(id); + if (d != null) i = d.createImage(); + if (i != null) images.put(icon, i); + } + } + } + break; + case 1: + break; + } + } + + return i; + } + + @Override + public void removeListener(ILabelProviderListener listener) { + } + + @Override + public boolean isLabelProperty(Object element, String property) { + return false; + } + + @Override + public void dispose() { + } + + @Override + public void addListener(ILabelProviderListener listener) { + } + }); + + List> l = ExternalExecutablesManager.load(); + if (l != null) executables.addAll(l); + + viewer.setInput(executables); + + viewer.addPostSelectionChangedListener(new ISelectionChangedListener() { + @Override + public void selectionChanged(SelectionChangedEvent event) { + updateButtons(); + } + }); + + updateButtons(); + + gc.dispose(); + + return panel; + } + + /** + * Updates the button states. + */ + protected void updateButtons() { + if (viewer != null) { + addButton.setEnabled(true); + + ISelection selection = viewer.getSelection(); + + boolean hasSelection = selection != null && !selection.isEmpty(); + int count = selection instanceof IStructuredSelection ? ((IStructuredSelection)selection).size() : 0; + + editButton.setEnabled(hasSelection && count == 1); + removeButton.setEnabled(hasSelection && count > 0); + } else { + addButton.setEnabled(false); + editButton.setEnabled(false); + removeButton.setEnabled(false); + } + } + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.PreferencePage#performDefaults() + */ + @Override + protected void performDefaults() { + if (!Platform.OS_WIN32.equals(Platform.getOS())) { + command.setText(""); //$NON-NLS-1$ + arguments.setText(""); //$NON-NLS-1$ + } + + String initialCwd = UIPlugin.getScopedPreferences().getDefaultString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD); + if (initialCwd == null || IPreferenceKeys.PREF_INITIAL_CWD_USER_HOME.equals(initialCwd) || "".equals(initialCwd.trim())) { //$NON-NLS-1$ + workingDir.select(0); + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_HOME.equals(initialCwd) || "${eclipse_home}".equals(initialCwd)) { //$NON-NLS-1$ + workingDir.select(1); + } else if (IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_WS.equals(initialCwd) || "${workspace_loc}".equals(initialCwd)) { //$NON-NLS-1$ + workingDir.select(2); + } else { + workingDir.setText(new Path(initialCwd).toOSString()); + } + + executables.clear(); + List> l = ExternalExecutablesManager.load(); + if (l != null) executables.addAll(l); + viewer.refresh(); + + super.performDefaults(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.PreferencePage#performOk() + */ + @Override + public boolean performOk() { + if (!Platform.OS_WIN32.equals(Platform.getOS())) { + String text = command.getText(); + IPath p = new Path(text.trim()); + UIPlugin.getScopedPreferences().putString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX, p.toFile().isFile() && p.toFile().canRead() && p.toFile().canExecute() ? p.toOSString() : null); + + text = arguments.getText(); + UIPlugin.getScopedPreferences().putString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX_ARGS, !"".equals(text.trim()) ? text.trim() : null); //$NON-NLS-1$ + } + + String text = workingDir.getText(); + if (text == null || Messages.PreferencePage_workingDir_userhome_label.equals(text) || "".equals(text.trim())) { //$NON-NLS-1$ + UIPlugin.getScopedPreferences().putString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD, null); + } else if (Messages.PreferencePage_workingDir_eclipsehome_label.equals(text)) { + UIPlugin.getScopedPreferences().putString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD, IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_HOME); + } else if (Messages.PreferencePage_workingDir_eclipsews_label.equals(text)) { + UIPlugin.getScopedPreferences().putString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD, IPreferenceKeys.PREF_INITIAL_CWD_ECLIPSE_WS); + } else { + try { + // Resolve possible dynamic variables + IStringVariableManager vm = VariablesPlugin.getDefault().getStringVariableManager(); + String resolved = vm.performStringSubstitution(text.trim()); + + IPath p = new Path(resolved); + UIPlugin.getScopedPreferences().putString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD, p.toFile().canRead() && p.toFile().isDirectory() ? text.trim() : null); + } catch (CoreException e) { + if (Platform.inDebugMode()) { + UIPlugin.getDefault().getLog().log(e.getStatus()); + } + } + } + + ExternalExecutablesManager.save(executables); + + return super.performOk(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.dialogs.DialogPage#dispose() + */ + @Override + public void dispose() { + for (Image i : images.values()) { + i.dispose(); + } + images.clear(); + super.dispose(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/preferences/PreferencesInitializer.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/preferences/PreferencesInitializer.java new file mode 100644 index 00000000000..3ebd30c698d --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/preferences/PreferencesInitializer.java @@ -0,0 +1,43 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Dirk Fauth - Bug 460496 + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.tm.terminal.view.core.preferences.ScopedEclipsePreferences; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.IPreferenceKeys; + +/** + * Terminal default preferences initializer. + */ +public class PreferencesInitializer extends AbstractPreferenceInitializer { + + /** + * Constructor. + */ + public PreferencesInitializer() { + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer#initializeDefaultPreferences() + */ + @Override + public void initializeDefaultPreferences() { + ScopedEclipsePreferences prefs = UIPlugin.getScopedPreferences(); + + prefs.putDefaultBoolean(IPreferenceKeys.PREF_REMOVE_TERMINATED_TERMINALS, true); + + prefs.putDefaultString(IPreferenceKeys.PREF_LOCAL_TERMINAL_INITIAL_CWD, IPreferenceKeys.PREF_INITIAL_CWD_USER_HOME); + prefs.putDefaultString(IPreferenceKeys.PREF_LOCAL_TERMINAL_DEFAULT_SHELL_UNIX, null); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/services/TerminalService.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/services/TerminalService.java new file mode 100644 index 00000000000..fcb6aa1c914 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/services/TerminalService.java @@ -0,0 +1,359 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.services; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.ISafeRunnable; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.SafeRunner; +import org.eclipse.core.runtime.Status; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.terminal.view.core.activator.CoreBundleActivator; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalTabListener; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.interfaces.IUIConstants; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.tm.terminal.view.ui.manager.ConsoleManager; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.PlatformUI; + +/** + * Terminal service implementation. + */ +@SuppressWarnings("restriction") +public class TerminalService implements ITerminalService { + /** + * The registered terminal tab dispose listeners. + */ + private final ListenerList terminalTabListeners = new ListenerList(); + + // Flag to remember if the terminal view has been restored or not. + private boolean fRestoringView; + + // Terminal tab events + + /** + * A terminal tab got disposed. + */ + public static final int TAB_DISPOSED = 1; + + /** + * Common terminal service runnable implementation. + */ + protected static abstract class TerminalServiceRunnable { + + /** + * Invoked to execute the terminal service runnable. + * + * @param id The terminals view id or null. + * @param secondaryId The terminals view secondary id or null. + * @param title The terminal tab title. Must not be null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * @param done The callback to invoke if the operation finished or null. + */ + public abstract void run(String id, String secondaryId, String title, ITerminalConnector connector, Object data, Done done); + + /** + * Returns if or if not to execute the runnable asynchronously. + *

              + * The method returns per default true. Overwrite to + * modify the behavior. + * + * @return True to execute the runnable asynchronously, false otherwise. + */ + public boolean isExecuteAsync() { return true; } + } + + /** + * Constructor + */ + public TerminalService() { + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.core.interfaces.ITerminalService#addTerminalTabListener(org.eclipse.tm.terminal.view.core.interfaces.ITerminalTabListener) + */ + @Override + public final void addTerminalTabListener(ITerminalTabListener listener) { + Assert.isNotNull(listener); + terminalTabListeners.add(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.core.interfaces.ITerminalService#removeTerminalTabListener(org.eclipse.tm.terminal.view.core.interfaces.ITerminalTabListener) + */ + @Override + public final void removeTerminalTabListener(ITerminalTabListener listener) { + Assert.isNotNull(listener); + terminalTabListeners.remove(listener); + } + + /** + * Convenience method for notifying the registered terminal tab listeners. + * + * @param event The terminal tab event. + * @param source The disposed tab item. Must not be null. + * @param data The custom data object associated with the disposed tab item or null. + */ + public final void fireTerminalTabEvent(final int event, final Object source, final Object data) { + Assert.isNotNull(source); + + // If no listener is registered, we are done here + if (terminalTabListeners.isEmpty()) return; + + // Get the list or currently registered listeners + // Loop the registered terminal tab listeners and invoke the proper method + for (final ITerminalTabListener listener : terminalTabListeners) { + ISafeRunnable job = new ISafeRunnable() { + @Override + public void handleException(Throwable exception) { + // already logged in Platform#run() + } + + @Override + public void run() throws Exception { + switch (event) { + case TAB_DISPOSED: + listener.terminalTabDisposed(source, data); + break; + default: + } + } + }; + SafeRunner.run(job); + } + } + + /** + * Executes the given runnable operation and invokes the given callback, if any, + * after the operation finished. + * + * @param properties The terminal properties. Must not be null. + * @param runnable The terminal service runnable. Must not be null. + * @param done The callback to invoke if the operation has been finished or null. + */ + protected final void executeServiceOperation(final Map properties, final TerminalServiceRunnable runnable, final Done done) { + Assert.isNotNull(properties); + Assert.isNotNull(runnable); + + // Extract the properties + String id = (String)properties.get(ITerminalsConnectorConstants.PROP_ID); + String secondaryId = (String)properties.get(ITerminalsConnectorConstants.PROP_SECONDARY_ID); + String title = (String)properties.get(ITerminalsConnectorConstants.PROP_TITLE); + Object data = properties.get(ITerminalsConnectorConstants.PROP_DATA); + + // Normalize the terminals console view id + id = normalizeId(id, data); + // Normalize the terminal console tab title + title = normalizeTitle(title, data); + + // Create the terminal connector instance + final ITerminalConnector connector = createTerminalConnector(properties); + if (connector == null) { + // Properties contain invalid connector arguments + if (done != null) { + Exception e = new IllegalArgumentException(Messages.TerminalService_error_cannotCreateConnector); + done.done(new Status(IStatus.ERROR, CoreBundleActivator.getUniqueIdentifier(), e.getLocalizedMessage(), e)); + } + return; + } + + // Finalize the used variables + final String finId = id; + final String finSecondaryId = secondaryId; + final String finTitle = title; + final Object finData = data; + + // Execute the operation + if (!runnable.isExecuteAsync()) { + runnable.run(finId, finSecondaryId, finTitle, connector, finData, done); + } + else { + try { + Display display = PlatformUI.getWorkbench().getDisplay(); + display.asyncExec(new Runnable() { + @Override + public void run() { + runnable.run(finId, finSecondaryId, finTitle, connector, finData, done); + } + }); + } + catch (Exception e) { + // if display is disposed, silently ignore. + } + } + } + + /** + * Normalize the terminals view id. + * + * @param id The terminals view id or null. + * @param data The custom data object or null. + * + * @return The normalized terminals console view id. + */ + protected String normalizeId(String id, Object data) { + return id != null ? id : IUIConstants.ID; + } + + /** + * Normalize the terminal tab title. + * + * @param title The terminal tab title or null. + * @param data The custom data object or null. + * + * @return The normalized terminal tab title. + */ + protected String normalizeTitle(String title, Object data) { + // If the title is explicitly specified, return as is + if (title != null) return title; + + // Return the default console title in all other cases + return Messages.TerminalService_defaultTitle; + } + + /** + * Creates the terminal connector configured within the given properties. + * + * @param properties The terminal console properties. Must not be null. + * @return The terminal connector or null. + */ + protected ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // The terminal connector result object + ITerminalConnector connector = null; + + // Get the launcher delegate id from the properties + String delegateId = (String)properties.get(ITerminalsConnectorConstants.PROP_DELEGATE_ID); + if (delegateId != null) { + // Get the launcher delegate + ILauncherDelegate delegate = LauncherDelegateManager.getInstance().getLauncherDelegate(delegateId, false); + if (delegate != null) { + // Create the terminal connector + connector = delegate.createTerminalConnector(properties); + } + } + + return connector; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.core.interfaces.ITerminalService#openConsole(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void openConsole(final Map properties, final Done done) { + Assert.isNotNull(properties); + final boolean restoringView = fRestoringView; + + executeServiceOperation(properties, new TerminalServiceRunnable() { + @Override + @SuppressWarnings("synthetic-access") + public void run(final String id, final String secondaryId, final String title, + final ITerminalConnector connector, final Object data, final Done done) { + if (restoringView) { + doRun(id, secondaryId, title, connector, data, done); + } else { + // First, restore the view. This opens consoles from the memento + fRestoringView = true; + ConsoleManager.getInstance().showConsoleView(id, secondaryId); + fRestoringView = false; + + // After that schedule opening the requested console + try { + Display display = PlatformUI.getWorkbench().getDisplay(); + display.asyncExec(new Runnable() { + @Override + public void run() { + doRun(id, secondaryId, title, connector, data, done); + } + }); + } + catch (Exception e) { + // if display is disposed, silently ignore. + } + } + } + + public void doRun(String id, String secondaryId, String title, ITerminalConnector connector, Object data, Done done) { + // Determine the terminal encoding + String encoding = (String)properties.get(ITerminalsConnectorConstants.PROP_ENCODING); + // Create the flags to pass on to openConsole + Map flags = new HashMap(); + flags.put("activate", Boolean.TRUE); //$NON-NLS-1$ + if (properties.get(ITerminalsConnectorConstants.PROP_FORCE_NEW) instanceof Boolean) { + flags.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, (Boolean)properties.get(ITerminalsConnectorConstants.PROP_FORCE_NEW)); + } + if (properties.get(ITerminalsConnectorConstants.PROP_DATA_NO_RECONNECT) instanceof Boolean) { + flags.put(ITerminalsConnectorConstants.PROP_DATA_NO_RECONNECT, (Boolean)properties.get(ITerminalsConnectorConstants.PROP_DATA_NO_RECONNECT)); + } + // Open the new console + CTabItem item; + if (secondaryId != null) + item = ConsoleManager.getInstance().openConsole(id, secondaryId, title, encoding, connector, data, flags); + else + item = ConsoleManager.getInstance().openConsole(id, title, encoding, connector, data, flags); + // Associate the original terminal properties with the tab item. + // This makes it easier to persist the connection data within the memento handler + if (item != null && !item.isDisposed()) item.setData("properties", properties); //$NON-NLS-1$ + + // Invoke the callback + if (done != null) done.done(Status.OK_STATUS); + } + }, done); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.core.interfaces.ITerminalService#closeConsole(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void closeConsole(final Map properties, final Done done) { + Assert.isNotNull(properties); + + executeServiceOperation(properties, new TerminalServiceRunnable() { + @Override + public void run(String id, String secondaryId, String title, ITerminalConnector connector, Object data, Done done) { + // Close the console + ConsoleManager.getInstance().closeConsole(id, title, connector, data); + // Invoke the callback + if (done != null) done.done(Status.OK_STATUS); + } + }, done); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.core.interfaces.ITerminalService#terminateConsole(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void terminateConsole(Map properties, Done done) { + Assert.isNotNull(properties); + + executeServiceOperation(properties, new TerminalServiceRunnable() { + @Override + public void run(String id, String secondaryId, String title, ITerminalConnector connector, Object data, Done done) { + // Close the console + ConsoleManager.getInstance().terminateConsole(id, title, connector, data); + // Invoke the callback + if (done != null) done.done(Status.OK_STATUS); + } + }, done); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/AbstractStreamsConnector.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/AbstractStreamsConnector.java new file mode 100644 index 00000000000..38cf5500dd1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/AbstractStreamsConnector.java @@ -0,0 +1,175 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.streams; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.ui.services.IDisposable; + +/** + * Streams connector implementation. + */ +public abstract class AbstractStreamsConnector extends TerminalConnectorImpl { + // Reference to the stdin monitor + private InputStreamMonitor stdInMonitor; + // Reference to the stdout monitor + private OutputStreamMonitor stdOutMonitor; + // Reference to the stderr monitor + private OutputStreamMonitor stdErrMonitor; + + // Reference to the list of stdout output listeners + private ITerminalServiceOutputStreamMonitorListener[] stdoutListeners = null; + // Reference to the list of stderr output listeners + private ITerminalServiceOutputStreamMonitorListener[] stderrListeners = null; + + /** + * Set the list of stdout listeners. + * + * @param listeners The list of stdout listeners or null. + */ + protected final void setStdoutListeners(ITerminalServiceOutputStreamMonitorListener[] listeners) { + this.stdoutListeners = listeners; + } + + /** + * Set the list of stderr listeners. + * + * @param listeners The list of stderr listeners or null. + */ + protected final void setStderrListeners(ITerminalServiceOutputStreamMonitorListener[] listeners) { + this.stderrListeners = listeners; + } + + /** + * Connect the given streams. The streams connector will wrap each stream + * with a corresponding terminal stream monitor. + * + * @param terminalControl The terminal control. Must not be null. + * @param stdin The stdin stream or null. + * @param stdout The stdout stream or null. + * @param stderr The stderr stream or null. + * @param localEcho Local echo on or off. + * @param lineSeparator The line separator used by the stream. + */ + protected void connectStreams(ITerminalControl terminalControl, OutputStream stdin, InputStream stdout, InputStream stderr, boolean localEcho, String lineSeparator) { + Assert.isNotNull(terminalControl); + + // Create the input stream monitor + if (stdin != null) { + stdInMonitor = createStdInMonitor(terminalControl, stdin, localEcho, lineSeparator); + // Register the connector if it implements IDisposable and stdout/stderr are not monitored + if (stdout == null && stderr == null && this instanceof IDisposable) stdInMonitor.addDisposable((IDisposable)this); + // Start the monitoring + stdInMonitor.startMonitoring(); + } + + // Create the output stream monitor + if (stdout != null) { + stdOutMonitor = createStdOutMonitor(terminalControl, stdout, lineSeparator); + // Register the connector if it implements IDisposable + if (this instanceof IDisposable) stdOutMonitor.addDisposable((IDisposable)this); + // Register the listeners + if (stdoutListeners != null) { + for (ITerminalServiceOutputStreamMonitorListener l : stdoutListeners) { + stdOutMonitor.addListener(l); + } + } + // Start the monitoring + stdOutMonitor.startMonitoring(); + } + + // Create the error stream monitor + if (stderr != null) { + stdErrMonitor = createStdErrMonitor(terminalControl, stderr, lineSeparator); + // Register the connector if it implements IDisposable and stdout is not monitored + if (stdout == null && this instanceof IDisposable) stdErrMonitor.addDisposable((IDisposable)this); + // Register the listeners + if (stderrListeners != null) { + for (ITerminalServiceOutputStreamMonitorListener l : stderrListeners) { + stdErrMonitor.addListener(l); + } + } + // Start the monitoring + stdErrMonitor.startMonitoring(); + } + } + + /** + * Creates an stdin monitor for the given terminal control and stdin stream. + * Subclasses may override to create a specialized stream monitor. + * + * @param terminalControl The terminal control. Must not be null. + * @param stdin The stdin stream or null. + * @param localEcho Local echo on or off. + * @param lineSeparator The line separator used by the stream. + * + * @return input stream monitor + */ + protected InputStreamMonitor createStdInMonitor(ITerminalControl terminalControl, OutputStream stdin, boolean localEcho, String lineSeparator) { + return new InputStreamMonitor(terminalControl, stdin, localEcho, lineSeparator); + } + + /** + * Creates an stdout monitor for the given terminal control and stdout stream. + * Subclasses may override to create a specialized stream monitor. + * + * @param terminalControl The terminal control. Must not be null. + * @param stdout The stdout stream or null. + * @param lineSeparator The line separator used by the stream. + * + * @return output stream monitor + */ + protected OutputStreamMonitor createStdOutMonitor(ITerminalControl terminalControl, InputStream stdout, String lineSeparator) { + return new OutputStreamMonitor(terminalControl, stdout, lineSeparator); + } + + /** + * Creates an stderr monitor for the given terminal control and stderr stream. + * Subclasses may override to create a specialized stream monitor. + * + * @param terminalControl The terminal control. Must not be null. + * @param stderr The stderr stream or null. + * @param lineSeparator The line separator used by the stream. + * + * @return output stream monitor + */ + protected OutputStreamMonitor createStdErrMonitor(ITerminalControl terminalControl, InputStream stderr, String lineSeparator) { + return new OutputStreamMonitor(terminalControl, stderr, lineSeparator); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#doDisconnect() + */ + @Override + protected void doDisconnect() { + // Dispose the streams + if (stdInMonitor != null) { stdInMonitor.dispose(); stdInMonitor = null; } + if (stdOutMonitor != null) { stdOutMonitor.dispose(); stdOutMonitor = null; } + if (stdErrMonitor != null) { stdErrMonitor.dispose(); stdErrMonitor = null; } + + super.doDisconnect(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getTerminalToRemoteStream() + */ + @Override + public OutputStream getTerminalToRemoteStream() { + return stdInMonitor; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/InputStreamMonitor.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/InputStreamMonitor.java new file mode 100644 index 00000000000..5f6e804fdc4 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/InputStreamMonitor.java @@ -0,0 +1,368 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.streams; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ILineSeparatorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.services.IDisposable; + +/** + * Input stream monitor implementation. + *

              + * Note: The input is coming from the terminal. Therefore, the input + * stream monitor is attached to the stdin stream of the monitored (remote) process. + */ +public class InputStreamMonitor extends OutputStream implements IDisposable { + // Reference to the parent terminal control + private final ITerminalControl terminalControl; + + // Reference to the monitored (output) stream + private final OutputStream stream; + + // Reference to the thread writing the stream + private volatile Thread thread; + + // Flag to mark the monitor disposed. When disposed, + // no further data is written from the monitored stream. + private volatile boolean disposed; + + // A list of object to dispose if this monitor is disposed + private final List disposables = new ArrayList(); + + // Queue to buffer the data to write to the output stream + private final Queue queue = new LinkedList(); + + // ***** Line separator replacement logic ***** + + private final static int TERMINAL_SENDS_CR = 0; + private final static int TERMINAL_SENDS_CRLF = 1; + private final static int PROGRAM_EXPECTS_LF = 0; + private final static int PROGRAM_EXPECTS_CRLF = 1; + private final static int PROGRAM_EXPECTS_CR = 2; + private final static int NO_CHANGE = 0; + private final static int CHANGE_CR_TO_LF = 1; + private final static int INSERT_LF_AFTER_CR = 2; + private final static int REMOVE_CR = 3; + private final static int REMOVE_LF = 4; + + // CRLF conversion table: + // + // Expected line separator --> | LF | CRLF | CR | + // ------------------------------------+-----------------+--------------------+----------------+ + // Local echo off - control sends CR | change CR to LF | insert LF after CR | no change | + // ------------------------------------+-----------------+--------------------+----------------+ + // Local echo on - control sends CRLF | remove CR | no change | remove LF | + // + private final static int[][] CRLF_REPLACEMENT = { + + {CHANGE_CR_TO_LF, INSERT_LF_AFTER_CR, NO_CHANGE}, + {REMOVE_CR, NO_CHANGE, REMOVE_LF} + }; + + private int replacement; + + /** + * Constructor. + * + * @param terminalControl The parent terminal control. Must not be null. + * @param stream The stream. Must not be null. + * @param localEcho Local echo on or off. + * @param lineSeparator The line separator used by the stream. + */ + public InputStreamMonitor(ITerminalControl terminalControl, OutputStream stream, boolean localEcho, String lineSeparator) { + super(); + + Assert.isNotNull(terminalControl); + this.terminalControl = terminalControl; + Assert.isNotNull(stream); + this.stream = stream; + + // Determine the line separator replacement setting + int terminalSends = localEcho ? TERMINAL_SENDS_CRLF : TERMINAL_SENDS_CR; + if (lineSeparator == null) { + replacement = NO_CHANGE; + } else { + int programExpects; + if (lineSeparator.equals(ILineSeparatorConstants.LINE_SEPARATOR_LF)) { + programExpects = PROGRAM_EXPECTS_LF; + } + else if (lineSeparator.equals(ILineSeparatorConstants.LINE_SEPARATOR_CR)) { + programExpects = PROGRAM_EXPECTS_CR; + } + else { + programExpects = PROGRAM_EXPECTS_CRLF; + } + replacement = CRLF_REPLACEMENT[terminalSends][programExpects]; + } + + } + + /** + * Returns the associated terminal control. + * + * @return The associated terminal control. + */ + protected final ITerminalControl getTerminalControl() { + return terminalControl; + } + + /** + * Adds the given disposable object to the list. The method will do nothing + * if either the disposable object is already part of the list or the monitor + * is disposed. + * + * @param disposable The disposable object. Must not be null. + */ + public final void addDisposable(IDisposable disposable) { + Assert.isNotNull(disposable); + if (!disposed && !disposables.contains(disposable)) disposables.add(disposable); + } + + /** + * Removes the disposable object from the list. + * + * @param disposable The disposable object. Must not be null. + */ + public final void removeDisposable(IDisposable disposable) { + Assert.isNotNull(disposable); + disposables.remove(disposable); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + // If already disposed --> return immediately + if (disposed) return; + + // Mark the monitor disposed + disposed = true; + + // Close the stream (ignore exceptions on close) + try { stream.close(); } catch (IOException e) { /* ignored on purpose */ } + // And interrupt the thread + close(); + + // Dispose all registered disposable objects + for (IDisposable disposable : disposables) disposable.dispose(); + // Clear the list + disposables.clear(); + } + + /** + * Close the terminal input stream monitor. + */ + @Override + public void close() { + // Not initialized -> return immediately + if (thread == null) return; + + // Copy the reference + final Thread oldThread = thread; + // Unlink the monitor from the thread + thread = null; + // And interrupt the writer thread + oldThread.interrupt(); + } + + /** + * Starts the terminal output stream monitor. + */ + public void startMonitoring() { + // If already initialized -> return immediately + if (thread != null) return; + + // Create a new runnable which is constantly reading from the stream + Runnable runnable = new Runnable() { + @Override + public void run() { + writeStream(); + } + }; + + // Create the writer thread + thread = new Thread(runnable, "Terminal Input Stream Monitor Thread"); //$NON-NLS-1$ + + // Configure the writer thread + thread.setDaemon(true); + + // Start the processing + thread.start(); + } + + + /** + * Reads from the queue and writes the read content to the stream. + */ + protected void writeStream() { + // Read from the queue and write to the stream until disposed + outer: while (thread != null && !disposed) { + byte[] data; + // If the queue is empty, wait until notified + synchronized(queue) { + while (queue.isEmpty()) { + if (disposed) break outer; + try { + queue.wait(); + } catch (InterruptedException e) { + break outer; + } + } + // Retrieves the queue head (is null if queue is empty (should never happen)) + data = queue.poll(); + } + if (data != null) { + try { + // Break up writes into max 1000 byte junks to avoid console input buffer overflows on Windows + int written = 0; + byte[] buf = new byte[1000]; + while (written < data.length) { + int len = Math.min(buf.length, data.length - written); + System.arraycopy(data, written, buf, 0, len); + // Write the data to the stream + stream.write(buf, 0, len); + written += len; + // Flush the stream immediately + stream.flush(); + // Wait a little between writes to allow input being processed + if (written < data.length) + Thread.sleep(100); + } + } catch (IOException e) { + // IOException received. If this is happening when already disposed -> ignore + if (!disposed) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.InputStreamMonitor_error_writingToStream, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + } + catch (InterruptedException e) { + break; + } + } + } + + // Dispose the stream + dispose(); + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(int) + */ + @Override + public void write(int b) throws IOException { + synchronized(queue) { + queue.add(new byte[] { (byte)b }); + queue.notifyAll(); + } + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(byte[], int, int) + */ + @Override + public void write(byte[] b, int off, int len) throws IOException { + // Write the whole block to the queue to avoid synchronization + // to happen for every byte. To do so, we have to avoid calling + // the super method. Therefore we have to do the same checking + // here as the base class does. + + // Null check. See the implementation in OutputStream. + if (b == null) throw new NullPointerException(); + + // Boundary check. See the implementation in OutputStream. + if ((off < 0) || (off > b.length) || (len < 0) || ((off + len) > b.length) || ((off + len) < 0)) { + throw new IndexOutOfBoundsException(); + } + else if (len == 0) { + return; + } + + // Make sure that the written block is not interlaced with other input. + synchronized(queue) { + // Preprocess the block to be written + byte[] processedBytes = onWriteContentToStream(b, off, len); + // If the returned array is not the original one, adjust offset and length + if (processedBytes != b) { + off = 0; len = processedBytes.length; b = processedBytes; + } + + // Get the content from the byte buffer specified by offset and length + byte[] bytes = new byte[len]; + int j = 0; + for (int i = 0 ; i < len ; i++) { + bytes[j++] = b[off + i]; + } + + queue.add(bytes); + queue.notifyAll(); + } + } + + /** + * Allow for processing of data from byte stream from the terminal before + * it is written to the output stream. If the returned byte array is different + * than the one that was passed in with the bytes argument, then the + * length value will be adapted. + * + * @param bytes The byte stream. Must not be null. + * @param off The offset. + * @param len the length. + * + * @return The processed byte stream. + * + */ + protected byte[] onWriteContentToStream(byte[] bytes, int off, int len) { + Assert.isNotNull(bytes); + + if (replacement != NO_CHANGE && len > 0) { + String origText = new String(bytes, off, len); + String text = null; + // + // TODO: check whether this is correct! new String(byte[], int, int) always uses the default + // encoding! + + if (replacement == CHANGE_CR_TO_LF) { + text = origText.replace('\r', '\n'); + } + else if (replacement == INSERT_LF_AFTER_CR) { + text = origText.replaceAll("\r\n|\r", "\r\n"); //$NON-NLS-1$ //$NON-NLS-2$ + } + else if (replacement == REMOVE_CR) { + text = origText.replaceAll(ILineSeparatorConstants.LINE_SEPARATOR_CR, ""); //$NON-NLS-1$ + } + else if (replacement == REMOVE_LF) { + text = origText.replaceAll(ILineSeparatorConstants.LINE_SEPARATOR_LF, ""); //$NON-NLS-1$ + } + + if (text != null && !origText.equals(text)) { + bytes = text.getBytes(); + } + } + + return bytes; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/OutputStreamMonitor.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/OutputStreamMonitor.java new file mode 100644 index 00000000000..92f7a6b0a8c --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/OutputStreamMonitor.java @@ -0,0 +1,320 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.streams; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.ListenerList; +import org.eclipse.core.runtime.Status; +import org.eclipse.osgi.util.NLS; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ILineSeparatorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.tracing.ITraceIds; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.services.IDisposable; + +/** + * Output stream monitor implementation. + *

              + * Note: The output is going to the terminal. Therefore, the output + * stream monitor is attached to the stdout and/or stderr stream of the monitored + * (remote) process. + */ +public class OutputStreamMonitor implements IDisposable { + // The default buffer size to use + private static final int BUFFER_SIZE = 8192; + + // Reference to the parent terminal control + private final ITerminalControl terminalControl; + + // Reference to the monitored (input) stream + private final InputStream stream; + + // The line separator used by the monitored (input) stream + private final String lineSeparator; + + // Reference to the thread reading the stream + private Thread thread; + + // Flag to mark the monitor disposed. When disposed, + // no further data is read from the monitored stream. + private boolean disposed; + + // A list of object to dispose if this monitor is disposed + private final List disposables = new ArrayList(); + + // The list of registered listener + private final ListenerList listeners; + + /** + * Constructor. + * + * @param terminalControl The parent terminal control. Must not be null. + * @param stream The stream. Must not be null. + * @param lineSeparator The line separator used by the stream. + */ + public OutputStreamMonitor(ITerminalControl terminalControl, InputStream stream, String lineSeparator) { + super(); + + Assert.isNotNull(terminalControl); + this.terminalControl = terminalControl; + Assert.isNotNull(stream); + this.stream = new BufferedInputStream(stream, BUFFER_SIZE); + + this.lineSeparator = lineSeparator; + + this.listeners = new ListenerList(); + } + + /** + * Register a streams data receiver listener. + * + * @param listener The listener. Must not be null. + */ + public final void addListener(ITerminalServiceOutputStreamMonitorListener listener) { + Assert.isNotNull(listener); + listeners.add(listener); + } + + /** + * Unregister a streams data receiver listener. + * + * @param listener The listener. Must not be null. + */ + public final void removeListener(ITerminalServiceOutputStreamMonitorListener listener) { + Assert.isNotNull(listener); + listeners.remove(listener); + } + + /** + * Adds the given disposable object to the list. The method will do nothing + * if either the disposable object is already part of the list or the monitor + * is disposed. + * + * @param disposable The disposable object. Must not be null. + */ + public final void addDisposable(IDisposable disposable) { + Assert.isNotNull(disposable); + if (!disposed && !disposables.contains(disposable)) disposables.add(disposable); + } + + /** + * Removes the disposable object from the list. + * + * @param disposable The disposable object. Must not be null. + */ + public final void removeDisposable(IDisposable disposable) { + Assert.isNotNull(disposable); + disposables.remove(disposable); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + // If already disposed --> return immediately + if (disposed) return; + + // Mark the monitor disposed + disposed = true; + + // Close the stream (ignore exceptions on close) + try { stream.close(); } catch (IOException e) { /* ignored on purpose */ } + + // Dispose all registered disposable objects + for (IDisposable disposable : disposables) disposable.dispose(); + // Clear the list + disposables.clear(); + } + + /** + * Starts the terminal output stream monitor. + */ + protected void startMonitoring() { + // If already initialized -> return immediately + if (thread != null) return; + + // Create a new runnable which is constantly reading from the stream + Runnable runnable = new Runnable() { + @Override + public void run() { + readStream(); + } + }; + + // Create the reader thread + thread = new Thread(runnable, "Terminal Output Stream Monitor Thread"); //$NON-NLS-1$ + + // Configure the reader thread + thread.setDaemon(true); + thread.setPriority(Thread.MIN_PRIORITY); + + // Start the processing + thread.start(); + } + + /** + * Returns the terminal control that this stream monitor is associated with. + */ + protected ITerminalControl getTerminalControl() { + return terminalControl; + } + + /** + * Reads from the output stream and write the read content + * to the terminal control output stream. + */ + void readStream() { + // Creates the read buffer + byte[] readBuffer = new byte[BUFFER_SIZE]; + + // We need to maintain UI responsiveness but still stream the content + // to the terminal control fast. Put the thread to a short sleep each second. + long sleepMarker = System.currentTimeMillis(); + + // Read from the stream until EOS is reached or the + // monitor is marked disposed. + int read = 0; + while (read >= 0 && !disposed) { + try { + // Read from the stream + read = stream.read(readBuffer); + // If some data has been read, append to the terminal + // control output stream + if (read > 0) { + // Allow for post processing the read content before appending + byte[] processedReadBuffer = onContentReadFromStream(readBuffer, read); + if (processedReadBuffer != readBuffer) { + read = processedReadBuffer.length; + } + terminalControl.getRemoteToTerminalOutputStream().write(processedReadBuffer, 0, read); + } + } catch (IOException e) { + // IOException received. If this is happening when already disposed -> ignore + if (!disposed) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.OutputStreamMonitor_error_readingFromStream, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + break; + } catch (NullPointerException e) { + // killing the stream monitor while reading can cause an NPE + // when reading from the stream + if (!disposed && thread != null) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + NLS.bind(Messages.OutputStreamMonitor_error_readingFromStream, e.getLocalizedMessage()), e); + UIPlugin.getDefault().getLog().log(status); + } + break; + } + + // See above -> Thread will go to sleep each second + if (System.currentTimeMillis() - sleepMarker > 1000) { + sleepMarker = System.currentTimeMillis(); + try { Thread.sleep(1); } catch (InterruptedException e) { /* ignored on purpose */ } + } + } + + // Dispose ourself + dispose(); + } + + /** + * Allow for processing of data from byte stream after it is read from + * client but before it is appended to the terminal. If the returned byte + * array is different than the one that was passed in with the byteBuffer + * argument, then the bytesRead value will be ignored and the full + * returned array will be written out. + * + * @param byteBuffer The byte stream. Must not be null. + * @param bytesRead The number of bytes that were read into the read buffer. + * @return The processed byte stream. + * + */ + protected byte[] onContentReadFromStream(byte[] byteBuffer, int bytesRead) { + Assert.isNotNull(byteBuffer); + + // If tracing is enabled, print out the decimal byte values read + if (UIPlugin.getTraceHandler().isSlotEnabled(0, ITraceIds.TRACE_OUTPUT_STREAM_MONITOR)) { + StringBuilder debug = new StringBuilder("byteBuffer [decimal, " + bytesRead + " bytes] : "); //$NON-NLS-1$ //$NON-NLS-2$ + for (int i = 0; i < bytesRead; i++) { + debug.append(Byte.valueOf(byteBuffer[i]).intValue()); + debug.append(' '); + } + System.out.println(debug.toString()); + } + + // Remember if the text got changed. + boolean changed = false; + + // How can me make sure that we don't mess with the encoding here? + String text = new String(byteBuffer, 0, bytesRead); + + // Shift-In (14) and Shift-Out(15) confuses the terminal widget + if (text.indexOf(14) != -1 || text.indexOf(15) != -1) { + text = text.replaceAll("\\x0e", "").replaceAll("\\x0f", ""); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + changed = true; + } + + // Check on the line separator setting + if (lineSeparator != null + && !ILineSeparatorConstants.LINE_SEPARATOR_CRLF.equals(lineSeparator)) { + String separator = ILineSeparatorConstants.LINE_SEPARATOR_LF.equals(lineSeparator) ? "\n" : "\r"; //$NON-NLS-1$ //$NON-NLS-2$ + String separator2 = ILineSeparatorConstants.LINE_SEPARATOR_LF.equals(lineSeparator) ? "\r" : "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + + if (text.indexOf(separator) != -1) { + String[] fragments = text.split(separator); + StringBuilder b = new StringBuilder(); + for (int i = 0; i < fragments.length; i++) { + String fragment = fragments[i]; + String nextFragment = i + 1 < fragments.length ? fragments[i + 1] : null; + b.append(fragment); + if (fragment.endsWith(separator2) || (nextFragment != null && nextFragment.startsWith(separator2))) { + // Both separators are found, just add the original separator + b.append(separator); + } else { + b.append("\n\r"); //$NON-NLS-1$ + } + } + if (!text.equals(b.toString())) { + text = b.toString(); + changed = true; + } + } + } + + // If changed, get the new bytes array + if (changed) { + byteBuffer = text.getBytes(); + bytesRead = byteBuffer.length; + } + + // If listeners are registered, invoke the listeners now. + if (listeners.size() > 0) { + for (Object candidate : listeners.getListeners()) { + if (!(candidate instanceof ITerminalServiceOutputStreamMonitorListener)) continue; + ((ITerminalServiceOutputStreamMonitorListener)candidate).onContentReadFromStream(byteBuffer, bytesRead); + } + } + + return byteBuffer; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsConnector.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsConnector.java new file mode 100644 index 00000000000..a62eb86a2c7 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsConnector.java @@ -0,0 +1,124 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.streams; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.NullSettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.ui.services.IDisposable; + +/** + * Streams connector implementation. + */ +public class StreamsConnector extends AbstractStreamsConnector implements IDisposable { + // Reference to the streams settings + private final StreamsSettings settings; + + /** + * Constructor. + */ + public StreamsConnector() { + this(new StreamsSettings()); + } + + /** + * Constructor. + * + * @param settings The streams settings. Must not be null + */ + public StreamsConnector(StreamsSettings settings) { + super(); + + Assert.isNotNull(settings); + this.settings = settings; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#connect(org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl) + */ + @Override + public void connect(ITerminalControl control) { + Assert.isNotNull(control); + super.connect(control); + + // Setup the listeners + setStdoutListeners(settings.getStdOutListeners()); + setStderrListeners(settings.getStdErrListeners()); + + // connect the streams + connectStreams(control, settings.getStdinStream(), settings.getStdoutStream(), settings.getStderrStream(), settings.isLocalEcho(), settings.getLineSeparator()); + + // Set the terminal control state to CONNECTED + control.setState(TerminalState.CONNECTED); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#isLocalEcho() + */ + @Override + public boolean isLocalEcho() { + return settings.isLocalEcho(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + disconnect(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.streams.AbstractStreamsConnector#doDisconnect() + */ + @Override + public void doDisconnect() { + // Dispose the streams + super.doDisconnect(); + + // Set the terminal control state to CLOSED. + fControl.setState(TerminalState.CLOSED); + } + + // ***** Process Connector settings handling ***** + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#getSettingsSummary() + */ + @Override + public String getSettingsSummary() { + return ""; //$NON-NLS-1$ + } + + @Override + public void setDefaultSettings() { + settings.load(new NullSettingsStore()); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#load(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void load(ISettingsStore store) { + settings.load(store); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl#save(org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore) + */ + @Override + public void save(ISettingsStore store) { + settings.save(store); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsLauncherDelegate.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsLauncherDelegate.java new file mode 100644 index 00000000000..8c126f1bac0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsLauncherDelegate.java @@ -0,0 +1,115 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.streams; + +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalConnectorExtension; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanel; +import org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; +import org.eclipse.tm.terminal.view.ui.launcher.AbstractLauncherDelegate; + +/** + * Streams launcher delegate implementation. + */ +public class StreamsLauncherDelegate extends AbstractLauncherDelegate { + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#needsUserConfiguration() + */ + @Override + public boolean needsUserConfiguration() { + return false; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#getPanel(org.eclipse.tm.terminal.view.ui.interfaces.IConfigurationPanelContainer) + */ + @Override + public IConfigurationPanel getPanel(IConfigurationPanelContainer container) { + return null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#execute(java.util.Map, org.eclipse.tm.terminal.view.core.interfaces.ITerminalService.Done) + */ + @Override + public void execute(Map properties, ITerminalService.Done done) { + Assert.isNotNull(properties); + + // Get the terminal service + ITerminalService terminal = TerminalServiceFactory.getService(); + // If not available, we cannot fulfill this request + if (terminal != null) { + terminal.openConsole(properties, done); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate#createTerminalConnector(java.util.Map) + */ + @Override + public ITerminalConnector createTerminalConnector(Map properties) { + Assert.isNotNull(properties); + + // Check for the terminal connector id + String connectorId = (String)properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (connectorId == null) connectorId = "org.eclipse.tm.terminal.connector.streams.StreamsConnector"; //$NON-NLS-1$ + + // Extract the streams properties + OutputStream stdin = (OutputStream)properties.get(ITerminalsConnectorConstants.PROP_STREAMS_STDIN); + InputStream stdout = (InputStream)properties.get(ITerminalsConnectorConstants.PROP_STREAMS_STDOUT); + InputStream stderr = (InputStream)properties.get(ITerminalsConnectorConstants.PROP_STREAMS_STDERR); + Object value = properties.get(ITerminalsConnectorConstants.PROP_LOCAL_ECHO); + boolean localEcho = value instanceof Boolean ? ((Boolean)value).booleanValue() : false; + String lineSeparator = (String)properties.get(ITerminalsConnectorConstants.PROP_LINE_SEPARATOR); + ITerminalServiceOutputStreamMonitorListener[] stdoutListeners = (ITerminalServiceOutputStreamMonitorListener[])properties.get(ITerminalsConnectorConstants.PROP_STDOUT_LISTENERS); + ITerminalServiceOutputStreamMonitorListener[] stderrListeners = (ITerminalServiceOutputStreamMonitorListener[])properties.get(ITerminalsConnectorConstants.PROP_STDERR_LISTENERS); + + // Construct the terminal settings store + ISettingsStore store = new SettingsStore(); + + // Construct the streams settings + StreamsSettings streamsSettings = new StreamsSettings(); + streamsSettings.setStdinStream(stdin); + streamsSettings.setStdoutStream(stdout); + streamsSettings.setStderrStream(stderr); + streamsSettings.setLocalEcho(localEcho); + streamsSettings.setLineSeparator(lineSeparator); + streamsSettings.setStdOutListeners(stdoutListeners); + streamsSettings.setStdErrListeners(stderrListeners); + // And save the settings to the store + streamsSettings.save(store); + + // Construct the terminal connector instance + ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorId); + if (connector != null) { + // Apply default settings + connector.setDefaultSettings(); + // And load the real settings + connector.load(store); + } + + return connector; + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsSettings.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsSettings.java new file mode 100644 index 00000000000..a7ca35fad50 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/streams/StreamsSettings.java @@ -0,0 +1,203 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.streams; + +import java.io.InputStream; +import java.io.OutputStream; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalServiceOutputStreamMonitorListener; +import org.eclipse.tm.terminal.view.ui.internal.SettingsStore; + +/** + * Streams connector settings implementation. + */ +public class StreamsSettings { + // Reference to the stdin stream + private OutputStream stdin; + // Reference to the stdout stream + private InputStream stdout; + // Reference to the stderr stream + private InputStream stderr; + // Flag to control the local echo + private boolean localEcho = true; + // The line separator setting + private String lineSeparator = null; + // The list of stdout output listeners + private ITerminalServiceOutputStreamMonitorListener[] stdoutListeners = null; + // The list of stderr output listeners + private ITerminalServiceOutputStreamMonitorListener[] stderrListeners = null; + + /** + * Sets the stdin stream instance. + * + * @param stdin The stream instance or null. + */ + public void setStdinStream(OutputStream stdin) { + this.stdin = stdin; + } + + /** + * Returns the stdin stream instance. + * + * @return The stream instance or null. + */ + public OutputStream getStdinStream() { + return stdin; + } + + /** + * Sets the stdout stream instance. + * + * @param stdout The stream instance or null. + */ + public void setStdoutStream(InputStream stdout) { + this.stdout = stdout; + } + + /** + * Returns the stdout stream instance. + * + * @return The stream instance or null. + */ + public InputStream getStdoutStream() { + return stdout; + } + + /** + * Sets the stderr stream instance. + * + * @param stderr The stream instance or null. + */ + public void setStderrStream(InputStream stderr) { + this.stderr = stderr; + } + + /** + * Returns the stderr stream instance. + * + * @return The stream instance or null. + */ + public InputStream getStderrStream() { + return stderr; + } + + /** + * Sets if the process requires a local echo from the terminal widget. + * + * @param value Specify true to enable the local echo, false otherwise. + */ + public void setLocalEcho(boolean value) { + this.localEcho = value; + } + + /** + * Returns true if the process requires a local echo + * from the terminal widget. + * + * @return True if local echo is enabled, false otherwise. + */ + public boolean isLocalEcho() { + return localEcho; + } + + /** + * Sets the stream line separator. + * + * @param separator The stream line separator null. + */ + public void setLineSeparator(String separator) { + this.lineSeparator = separator; + } + + /** + * Returns the stream line separator. + * + * @return The stream line separator or null. + */ + public String getLineSeparator() { + return lineSeparator; + } + + /** + * Sets the list of stdout listeners. + * + * @param listeners The list of stdout listeners or null. + */ + public void setStdOutListeners(ITerminalServiceOutputStreamMonitorListener[] listeners) { + this.stdoutListeners = listeners; + } + + /** + * Returns the list of stdout listeners. + * + * @return The list of stdout listeners or null. + */ + public ITerminalServiceOutputStreamMonitorListener[] getStdOutListeners() { + return stdoutListeners; + } + + /** + * Sets the list of stderr listeners. + * + * @param listeners The list of stderr listeners or null. + */ + public void setStdErrListeners(ITerminalServiceOutputStreamMonitorListener[] listeners) { + this.stderrListeners = listeners; + } + + /** + * Returns the list of stderr listeners. + * + * @return The list of stderr listeners or null. + */ + public ITerminalServiceOutputStreamMonitorListener[] getStdErrListeners() { + return stderrListeners; + } + + /** + * Loads the streams settings from the given settings store. + * + * @param store The settings store. Must not be null. + */ + public void load(ISettingsStore store) { + Assert.isNotNull(store); + localEcho = Boolean.parseBoolean(store.get("LocalEcho", Boolean.FALSE.toString())); //$NON-NLS-1$ + lineSeparator = store.get("LineSeparator", null); //$NON-NLS-1$ + if (store instanceof SettingsStore) { + stdin = (OutputStream)((SettingsStore)store).getSettings().get("stdin"); //$NON-NLS-1$ + stdout = (InputStream)((SettingsStore)store).getSettings().get("stdout"); //$NON-NLS-1$ + stderr = (InputStream)((SettingsStore)store).getSettings().get("stderr"); //$NON-NLS-1$ + stdoutListeners = (ITerminalServiceOutputStreamMonitorListener[])((SettingsStore)store).getSettings().get("StdOutListeners"); //$NON-NLS-1$ + stderrListeners = (ITerminalServiceOutputStreamMonitorListener[])((SettingsStore)store).getSettings().get("StdErrListeners"); //$NON-NLS-1$ + } + } + + /** + * Saves the process settings to the given settings store. + * + * @param store The settings store. Must not be null. + */ + public void save(ISettingsStore store) { + Assert.isNotNull(store); + store.put("LocalEcho", Boolean.toString(localEcho)); //$NON-NLS-1$ + store.put("LineSeparator", lineSeparator); //$NON-NLS-1$ + if (store instanceof SettingsStore) { + ((SettingsStore)store).getSettings().put("stdin", stdin); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("stdout", stdout); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("stderr", stderr); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("StdOutListeners", stdoutListeners); //$NON-NLS-1$ + ((SettingsStore)store).getSettings().put("StdErrListeners", stderrListeners); //$NON-NLS-1$ + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabCommandFieldHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabCommandFieldHandler.java new file mode 100644 index 00000000000..067586571e0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabCommandFieldHandler.java @@ -0,0 +1,104 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.CommandInputFieldWithHistory; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.ui.services.IDisposable; + +/** + * Tab command input field handler implementation. + */ +public class TabCommandFieldHandler implements IDisposable, IAdaptable { + // Reference to the parent tab folder manager + private final TabFolderManager tabFolderManager; + // Reference to the associated tab + private final CTabItem item; + + // Reference to the command input field + private CommandInputFieldWithHistory field; + // The command field history + private String history; + + /** + * Constructor. + * + * @param tabFolderManager The parent tab folder manager. Must not be null + * @param item The associated tab item. Must not be null. + */ + public TabCommandFieldHandler(TabFolderManager tabFolderManager, CTabItem item) { + Assert.isNotNull(tabFolderManager); + this.tabFolderManager = tabFolderManager; + Assert.isNotNull(item); + this.item = item; + } + + /* (non-Javadoc) + * @see org.eclipse.ui.services.IDisposable#dispose() + */ + @Override + public void dispose() { + field = null; + history = null; + } + + /* (non-Javadoc) + * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Object getAdapter(Class adapter) { + if (TabFolderManager.class.equals(adapter)) { + return tabFolderManager; + } + if (CTabItem.class.equals(adapter)) { + return item; + } + return null; + } + + /** + * Returns if or if not the associated tab item has the command input field enabled. + * + * @return True if the command input field is enabled, false otherwise. + */ + public boolean hasCommandInputField() { + return field != null; + } + + /** + * Set the command input field on or off. + * + * @param on True for on, false for off. + */ + public void setCommandInputField(boolean on) { + // save the old history + if (field != null) { + history = field.getHistory(); + field = null; + } + + if (on) { + field = new CommandInputFieldWithHistory(100); + field.setHistory(history); + } + + // Apply to the terminal control + Assert.isTrue(!item.isDisposed()); + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal != null) terminal.setCommandInputField(field); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabDisposeListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabDisposeListener.java new file mode 100644 index 00000000000..3cc4186a5b1 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabDisposeListener.java @@ -0,0 +1,83 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.widgets.Control; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.terminal.view.core.TerminalServiceFactory; +import org.eclipse.tm.terminal.view.core.interfaces.ITerminalService; +import org.eclipse.tm.terminal.view.ui.services.TerminalService; + +/** + * Terminal tab default dispose listener implementation. + */ +public class TabDisposeListener implements DisposeListener { + private final TabFolderManager parentTabFolderManager; + + /** + * Constructor. + * + * @param parentTabFolderManager The parent tab folder manager. Must not be null + */ + public TabDisposeListener(TabFolderManager parentTabFolderManager) { + Assert.isNotNull(parentTabFolderManager); + this.parentTabFolderManager = parentTabFolderManager; + } + + /** + * Returns the parent terminal console tab folder manager instance. + * + * @return The parent terminal console tab folder manager instance. + */ + protected final TabFolderManager getParentTabFolderManager() { + return parentTabFolderManager; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) + */ + @Override + public void widgetDisposed(DisposeEvent e) { + // If a tab item gets disposed, we have to dispose the terminal as well + if (e.getSource() instanceof CTabItem) { + // Get the terminal control (if any) from the tab item + Object candidate = ((CTabItem)e.getSource()).getData(); + if (candidate instanceof ITerminalViewControl) { + ITerminalViewControl terminal = (ITerminalViewControl)candidate; + // Keep the context menu from being disposed + terminal.getControl().setMenu(null); + terminal.disposeTerminal(); + } + // Dispose the command input field handler + parentTabFolderManager.disposeTabCommandFieldHandler((CTabItem)e.getSource()); + // Dispose the tab item control + Control control = ((CTabItem) e.getSource()).getControl(); + if (control != null) control.dispose(); + + // If all items got removed, we have to switch back to the empty page control + if (parentTabFolderManager.getTabFolder() != null && parentTabFolderManager.getTabFolder().getItemCount() == 0) { + parentTabFolderManager.getParentView().switchToEmptyPageControl(); + } + // Fire selection changed event + parentTabFolderManager.fireSelectionChanged(); + // Fire the terminal console disposed event + ITerminalService service = TerminalServiceFactory.getService(); + if (service instanceof TerminalService) { + ((TerminalService)service).fireTerminalTabEvent(TerminalService.TAB_DISPOSED, e.getSource(), ((CTabItem)e.getSource()).getData("customData")); //$NON-NLS-1$ + } + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java new file mode 100644 index 00000000000..eaf36785aef --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderManager.java @@ -0,0 +1,860 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.action.IStatusLineManager; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.dnd.Clipboard; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.events.DisposeEvent; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.events.MouseListener; +import org.eclipse.swt.events.SelectionListener; +import org.eclipse.swt.graphics.Image; +import org.eclipse.swt.layout.FillLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.tm.internal.terminal.control.ITerminalListener; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.TerminalViewControlFactory; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalConnector; +import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.interfaces.ImageConsts; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.ui.PlatformUI; + +/** + * Terminal tab folder manager. + */ +public class TabFolderManager extends PlatformObject implements ISelectionProvider { + // Reference to the parent terminal consoles view + private final ITerminalsView parentView; + // Reference to the selection listener instance + private final SelectionListener selectionListener; + + /** + * List of selection changed listeners. + */ + private final List selectionChangedListeners = new ArrayList(); + + /** + * Map of tab command input field handler per tab item + */ + private final Map commandFieldHandler = new HashMap(); + + /** + * The terminal control selection listener implementation. + */ + private class TerminalControlSelectionListener implements DisposeListener, MouseListener { + private final ITerminalViewControl terminal; + private boolean selectMode; + + /** + * Constructor. + * + * @param terminal The terminal control. Must not be null. + */ + public TerminalControlSelectionListener(ITerminalViewControl terminal) { + Assert.isNotNull(terminal); + this.terminal = terminal; + + // Register ourself as the required listener + terminal.getControl().addDisposeListener(this); + terminal.getControl().addMouseListener(this); + } + + /** + * Returns the associated terminal view control. + * + * @return The terminal view control. + */ + protected final ITerminalViewControl getTerminal() { + return terminal; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.DisposeListener#widgetDisposed(org.eclipse.swt.events.DisposeEvent) + */ + @Override + public void widgetDisposed(DisposeEvent e) { + // Widget got disposed, check if it is ours + // If a tab item gets disposed, we have to dispose the terminal as well + if (e.getSource().equals(terminal.getControl())) { + // Remove as listener + getTerminal().getControl().removeDisposeListener(this); + getTerminal().getControl().removeMouseListener(this); + } + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseDown(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDown(MouseEvent e) { + // Left button down -> select mode starts + if (e.button == 1) selectMode = true; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseUp(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseUp(MouseEvent e) { + if (e.button == 1 && selectMode) { + selectMode = false; + // Fire a selection changed event with the terminal controls selection + try { + Display display = PlatformUI.getWorkbench().getDisplay(); + display.asyncExec(new Runnable() { + @Override + public void run() { + fireSelectionChanged(new StructuredSelection(getTerminal().getSelection())); + } + }); + } + catch (Exception ex) { + // if display is disposed, silently ignore. + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent) + */ + @Override + public void mouseDoubleClick(MouseEvent e) { + } + } + + /** + * Constructor. + * + * @param parentView The parent terminals console view. Must not be null. + */ + public TabFolderManager(ITerminalsView parentView) { + super(); + Assert.isNotNull(parentView); + this.parentView = parentView; + + // Attach a selection listener to the tab folder + selectionListener = doCreateTabFolderSelectionListener(this); + if (getTabFolder() != null) getTabFolder().addSelectionListener(selectionListener); + } + + /** + * Creates the terminal console tab folder selection listener instance. + * + * @param parent The parent terminal console tab folder manager. Must not be null. + * @return The selection listener instance. + */ + protected TabFolderSelectionListener doCreateTabFolderSelectionListener(TabFolderManager parent) { + Assert.isNotNull(parent); + return new TabFolderSelectionListener(parent); + } + + /** + * Returns the parent terminal consoles view. + * + * @return The terminal consoles view instance. + */ + protected final ITerminalsView getParentView() { + return parentView; + } + + /** + * Returns the tab folder associated with the parent view. + * + * @return The tab folder or null. + */ + @SuppressWarnings("cast") + protected final CTabFolder getTabFolder() { + return (CTabFolder) getParentView().getAdapter(CTabFolder.class); + } + + /** + * Returns the selection changed listeners currently registered. + * + * @return The registered selection changed listeners or an empty array. + */ + protected final ISelectionChangedListener[] getSelectionChangedListeners() { + return selectionChangedListeners.toArray(new ISelectionChangedListener[selectionChangedListeners.size()]); + } + + /** + * Dispose the tab folder manager instance. + */ + public void dispose() { + // Dispose the selection listener + if (getTabFolder() != null && !getTabFolder().isDisposed()) getTabFolder().removeSelectionListener(selectionListener); + // Dispose the tab command field handler + for (TabCommandFieldHandler handler : commandFieldHandler.values()) { + handler.dispose(); + } + commandFieldHandler.clear(); + } + + /** + * Creates a new tab item with the given title and connector. + * + * @param title The tab title. Must not be null. + * @param encoding The terminal encoding or null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * @param flags The flags controlling how the console is opened or null to use defaults. + * + * @return The created tab item or null if failed. + */ + @SuppressWarnings({ "unused", "cast" }) + public CTabItem createTabItem(String title, String encoding, ITerminalConnector connector, Object data, Map flags) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + + // The result tab item + CTabItem item = null; + + // Get the tab folder from the parent viewer + CTabFolder tabFolder = getTabFolder(); + if (tabFolder != null) { + // Generate a unique title string for the new tab item (must be called before creating the item itself) + title = makeUniqueTitle(title, tabFolder); + // Create the tab item + item = new CTabItem(tabFolder, SWT.CLOSE); + // Set the tab item title + item.setText(title); + // Set the tab icon + Image image = getTabItemImage(connector, data); + if (image != null) item.setImage(image); + + // Setup the tab item listeners + setupTerminalTabListeners(item); + + // Create the composite to create the terminal control within + Composite composite = new Composite(tabFolder, SWT.NONE); + composite.setLayout(new FillLayout()); + // Associate the composite with the tab item + item.setControl(composite); + + // Refresh the layout + tabFolder.getParent().layout(true); + + // Create the terminal control + ITerminalViewControl terminal = TerminalViewControlFactory.makeControl(doCreateTerminalTabTerminalListener(this, item), composite, new ITerminalConnector[] { connector }, true); + if (terminal instanceof ITerminalControl) { + Object value = flags != null ? flags.get(ITerminalsConnectorConstants.PROP_DATA_NO_RECONNECT) : null; + boolean noReconnect = value instanceof Boolean ? ((Boolean)value).booleanValue() : false; + ((ITerminalControl)terminal).setConnectOnEnterIfClosed(!noReconnect); + } + + // Add middle mouse button paste support + addMiddleMouseButtonPasteSupport(terminal); + // Add the "selection" listener to the terminal control + new TerminalControlSelectionListener(terminal); + // Configure the terminal encoding + try { terminal.setEncoding(encoding); } catch (UnsupportedEncodingException e) { /* ignored on purpose */ } + // Associated the terminal with the tab item + item.setData(terminal); + // Associated the custom data node with the tab item (if any) + if (data != null) item.setData("customData", data); //$NON-NLS-1$ + + // Overwrite the text canvas help id + String contextHelpId = getParentView().getContextHelpId(); + if (contextHelpId != null) { + PlatformUI.getWorkbench().getHelpSystem().setHelp(terminal.getControl(), contextHelpId); + } + + // Set the context menu + TabFolderMenuHandler menuHandler = (TabFolderMenuHandler) getParentView().getAdapter(TabFolderMenuHandler.class); + if (menuHandler != null) { + Menu menu = (Menu)menuHandler.getAdapter(Menu.class); + if (menu != null) { + // One weird occurrence of IllegalArgumentException: Widget has wrong parent. + // Inspecting the code, this seem extremely unlikely. The terminal is created + // from a composite parent, the composite parent from the tab folder and the menu + // from the tab folder. Means, at the end all should have the same menu shell, shouldn't they? + try { + terminal.getControl().setMenu(menu); + } catch (IllegalArgumentException e) { + // Log exception only if debug mode is set to 1. + if (UIPlugin.getTraceHandler().isSlotEnabled(1, null)) { + e.printStackTrace(); + } + } + } + } + + // Select the created item within the tab folder + tabFolder.setSelection(item); + + // Set the connector + terminal.setConnector(connector); + + // And connect the terminal + terminal.connectTerminal(); + + // Fire selection changed event + fireSelectionChanged(); + } + + // Return the create tab item finally. + return item; + } + + /** + * Used for DnD of terminal tab items between terminal views + *

              + * Create a new tab item in the "dropped" terminal view using the + * information stored in the given item. + * + * @param oldItem The old dragged tab item. Must not be null. + * @return The new dropped tab item. + */ + @SuppressWarnings({ "unchecked", "cast" }) + public CTabItem cloneTabItemAfterDrop(CTabItem oldItem) { + Assert.isNotNull(oldItem); + + ITerminalViewControl terminal = (ITerminalViewControl)oldItem.getData(); + ITerminalConnector connector = terminal.getTerminalConnector(); + Object data = oldItem.getData("customData"); //$NON-NLS-1$ + Map properties = (Map)oldItem.getData("properties"); //$NON-NLS-1$ + String title = oldItem.getText(); + + // The result tab item + CTabItem item = null; + + // Get the tab folder from the parent viewer + CTabFolder tabFolder = getTabFolder(); + if (tabFolder != null) { + // Generate a unique title string for the new tab item (must be called before creating the item itself) + title = makeUniqueTitle(title, tabFolder); + // Create the tab item + item = new CTabItem(tabFolder, SWT.CLOSE); + // Set the tab item title + item.setText(title); + // Set the tab icon + Image image = getTabItemImage(connector, data); + if (image != null) item.setImage(image); + + // Setup the tab item listeners + setupTerminalTabListeners(item); + // Move the terminal listener to the new item + TabTerminalListener.move(oldItem, item); + + // Create the composite to create the terminal control within + Composite composite = new Composite(tabFolder, SWT.NONE); + composite.setLayout(new FillLayout()); + // Associate the composite with the tab item + item.setControl(composite); + + // Refresh the layout + tabFolder.getParent().layout(true); + + // Remember terminal state + TerminalState oldState = terminal.getState(); + + // Keep the context menu from being disposed + terminal.getControl().setMenu(null); + + // change the "parent". + Assert.isTrue(terminal instanceof ITerminalControl); + ((ITerminalControl)terminal).setupTerminal(composite); + + // Add middle mouse button paste support + addMiddleMouseButtonPasteSupport(terminal); + + item.setData(terminal); + + // Associate the custom data node with the tab item (if any) + if (data != null) item.setData("customData", data); //$NON-NLS-1$ + // Associate the properties with the tab item (if any) + if (properties != null) item.setData("properties", properties); //$NON-NLS-1$ + + // Overwrite the text canvas help id + String contextHelpId = getParentView().getContextHelpId(); + if (contextHelpId != null) { + PlatformUI.getWorkbench().getHelpSystem().setHelp(terminal.getControl(), contextHelpId); + } + + // Set the context menu + TabFolderMenuHandler menuHandler = (TabFolderMenuHandler) getParentView().getAdapter(TabFolderMenuHandler.class); + if (menuHandler != null) { + Menu menu = (Menu)menuHandler.getAdapter(Menu.class); + if (menu != null) { + // One weird occurrence of IllegalArgumentException: Widget has wrong parent. + // Inspecting the code, this seem extremely unlikely. The terminal is created + // from a composite parent, the composite parent from the tab folder and the menu + // from the tab folder. Means, at the end all should have the same menu shell, shouldn't they? + try { + terminal.getControl().setMenu(menu); + } catch (IllegalArgumentException e) { + // Log exception only if debug mode is set to 1. + if (UIPlugin.getTraceHandler().isSlotEnabled(1, null)) { + e.printStackTrace(); + } + } + } + } + + // Select the created item within the tab folder + tabFolder.setSelection(item); + + // Set the connector + terminal.setConnector(connector); + + // needed to get the focus and cursor + Assert.isTrue(terminal instanceof ITerminalControl); + ((ITerminalControl)terminal).setState(oldState); + + // Fire selection changed event + fireSelectionChanged(); + } + + // Return the create tab item finally. + return item; + } + + + protected void addMiddleMouseButtonPasteSupport(final ITerminalViewControl terminal) { + terminal.getControl().addMouseListener(new MouseAdapter(){ + @Override + public void mouseDown(MouseEvent e) { + // paste when the middle button is clicked + if (e.button == 2) { + Clipboard clipboard = terminal.getClipboard(); + if (clipboard.isDisposed()) return; + int clipboardType = DND.SELECTION_CLIPBOARD; + if (clipboard.getAvailableTypes(clipboardType).length == 0) + // use normal clipboard if selection clipboard is not available + clipboardType = DND.CLIPBOARD; + String text = (String) clipboard.getContents(TextTransfer.getInstance(), clipboardType); + if (text != null && text.length() > 0) + terminal.pasteString(text); + } + } + }); + } + + /** + * Generate a unique title string based on the given proposal. + * + * @param proposal The proposal. Must not be null. + * @return The unique title string. + */ + protected String makeUniqueTitle(String proposal, CTabFolder tabFolder) { + Assert.isNotNull(proposal); + Assert.isNotNull(tabFolder); + + String title = proposal; + int index = 0; + + // Loop all existing tab items and check the titles. We have to remember + // all found titles as modifying the proposal might in turn conflict again + // with the title of a tab already checked. + List titles = new ArrayList(); + for (CTabItem item : tabFolder.getItems()) { + // Get the tab item title + titles.add(item.getText()); + } + // Make the proposal unique be appending () against all known titles. + while (titles.contains(title)) title = proposal + " (" + ++index + ")"; //$NON-NLS-1$ //$NON-NLS-2$ + + return title; + } + + /** + * Setup the terminal console tab item listeners. + * + * @param item The tab item. Must not be null. + */ + protected void setupTerminalTabListeners(final CTabItem item) { + Assert.isNotNull(item); + + // Create and associate the disposal listener + DisposeListener disposeListener = doCreateTerminalTabDisposeListener(this); + + // store the listener to make access easier e.g. needed in DnD + item.setData("disposeListener", disposeListener); //$NON-NLS-1$ + item.addDisposeListener(disposeListener); + } + + /** + * Creates a new terminal console tab terminal listener instance. + * + * @param tabFolderManager The tab folder manager. Must not be null. + * @param item The tab item. Must not be null. + * + * @return The terminal listener instance. + */ + protected ITerminalListener doCreateTerminalTabTerminalListener(TabFolderManager tabFolderManager, CTabItem item) { + Assert.isNotNull(item); + return new TabTerminalListener(tabFolderManager, item); + } + + /** + * Creates a new terminal console tab dispose listener instance. + * + * @param parent The parent terminal console tab folder manager. Must not be null. + * @return The dispose listener instance. + */ + protected DisposeListener doCreateTerminalTabDisposeListener(TabFolderManager parent) { + Assert.isNotNull(parent); + return new TabDisposeListener(parent); + } + + /** + * Returns the tab item image. + * + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * + * @return The tab item image or null. + */ + protected Image getTabItemImage(ITerminalConnector connector, Object data) { + Assert.isNotNull(connector); + return UIPlugin.getImage(ImageConsts.VIEW_Terminals); + } + + /** + * Lookup a tab item with the given title and the given terminal connector. + *

              + * Note: The method will handle unified tab item titles itself. + * + * @param title The tab item title. Must not be null. + * @param connector The terminal connector. Must not be null. + * @param data The custom terminal data node or null. + * + * @return The corresponding tab item or null. + */ + public CTabItem findTabItem(String title, ITerminalConnector connector, Object data) { + Assert.isNotNull(title); + Assert.isNotNull(connector); + + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return null; + + // Loop all existing tab items and try to find a matching title + for (CTabItem item : tabFolder.getItems()) { + // Disposed items cannot be matched + if (item.isDisposed()) continue; + // Get the title from the current tab item + String itemTitle = item.getText(); + // The terminal console state might be signaled to the user via the + // terminal console tab title. Filter out any prefix "<.*>\s*". + itemTitle = itemTitle.replaceFirst("^<.*>\\s*", ""); //$NON-NLS-1$ //$NON-NLS-2$ + if (itemTitle.startsWith(title)) { + // The title string matches -> double check with the terminal connector + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + ITerminalConnector connector2 = terminal.getTerminalConnector(); + // If the connector id and name matches -> check on the settings + if (connector.getId().equals(connector2.getId()) && connector.getName().equals(connector2.getName())) { + if (!connector.isInitialized()) { + // an uninitialized connector does not yield a sensible summary + return item; + } + String summary = connector.getSettingsSummary(); + String summary2 = connector2.getSettingsSummary(); + // If we have matching settings -> we've found the matching item + if (summary.equals(summary2)) return item; + } + } + } + + return null; + } + + /** + * Make the given tab item the active tab and bring the tab to the top. + * + * @param item The tab item. Must not be null. + */ + public void bringToTop(CTabItem item) { + Assert.isNotNull(item); + + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return; + + // Set the given tab item as selection to the tab folder + tabFolder.setSelection(item); + // Fire selection changed event + fireSelectionChanged(); + } + + /** + * Returns the currently active tab. + * + * @return The active tab item or null if none. + */ + public CTabItem getActiveTabItem() { + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return null; + + return tabFolder.getSelection(); + } + + /** + * Remove all terminated tab items. + */ + public void removeTerminatedItems() { + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) return; + + // Loop the items and check for terminated status + for (CTabItem item: tabFolder.getItems()) { + // Disposed items cannot be matched + if (item.isDisposed()) continue; + // Check if the item is terminated + if (isTerminatedTabItem(item)) { + // item is terminated -> dispose + item.dispose(); + } + } + } + + /** + * Checks if the given tab item represents a terminated console. Subclasses may + * overwrite this method to extend the definition of terminated. + * + * @param item The tab item or null. + * @return True if the tab item represents a terminated console, false otherwise. + */ + protected boolean isTerminatedTabItem(CTabItem item) { + // Null items or disposed items cannot be matched + if (item == null || item.isDisposed()) return false; + + // First, match the item title. If it contains "", the item can be removed + String itemTitle = item.getText(); + if (itemTitle != null && itemTitle.contains("")) { //$NON-NLS-1$ + return true; + } + // Second, check if the associated terminal control is closed + // The title string matches -> double check with the terminal connector + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal != null && terminal.getState() == TerminalState.CLOSED) { + return true; + } + + return false; + } + + /** + * Returns the command input field handler for the given tab item. + * + * @param item The tab item or null. + * @return The command input field handler or null. + */ + public final TabCommandFieldHandler getTabCommandFieldHandler(CTabItem item) { + // Null items or disposed items cannot be matched + if (item == null || item.isDisposed()) return null; + + TabCommandFieldHandler handler = commandFieldHandler.get(item); + if (handler == null) { + handler = createTabCommandFieldHandler(this, item); + Assert.isNotNull(handler); + commandFieldHandler.put(item, handler); + } + return handler; + } + + /** + * Create the command input field handler for the given tab item. + * + * @param tabFolderManager The parent tab folder manager. Must not be null + * @param item The associated tab item. Must not be null. + * + * @return The command input field handler. Must not be null. + * + * @since 4.1 + */ + protected TabCommandFieldHandler createTabCommandFieldHandler(TabFolderManager tabFolderManager, CTabItem item) { + return new TabCommandFieldHandler(tabFolderManager, item); + } + + /** + * Dispose the command input field handler for the given tab item. + * + * @param item The tab item or null. + */ + protected void disposeTabCommandFieldHandler(CTabItem item) { + // Null items or disposed items cannot be matched + if (item == null || item.isDisposed()) return; + + TabCommandFieldHandler handler = commandFieldHandler.remove(item); + if (handler != null) handler.dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#addSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + @Override + public void addSelectionChangedListener(ISelectionChangedListener listener) { + if (listener != null && !selectionChangedListeners.contains(listener)) selectionChangedListeners.add(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#removeSelectionChangedListener(org.eclipse.jface.viewers.ISelectionChangedListener) + */ + @Override + public void removeSelectionChangedListener(ISelectionChangedListener listener) { + if (listener != null) selectionChangedListeners.remove(listener); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#getSelection() + */ + @Override + public ISelection getSelection() { + CTabItem activeTabItem = getActiveTabItem(); + return activeTabItem != null ? new StructuredSelection(activeTabItem) : new StructuredSelection(); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionProvider#setSelection(org.eclipse.jface.viewers.ISelection) + */ + @Override + public void setSelection(ISelection selection) { + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + // The first selection element which is a CTabItem will become the active item + Iterator iterator = ((IStructuredSelection)selection).iterator(); + while (iterator.hasNext()) { + Object candidate = iterator.next(); + if (candidate instanceof CTabItem) { bringToTop((CTabItem)candidate); return; } + } + } + // fire a changed event in any case + fireSelectionChanged(selection); + } + + /** + * Fire the selection changed event to the registered listeners. + */ + protected void fireSelectionChanged() { + updateStatusLine(); + fireSelectionChanged(getSelection()); + } + + /** + * Fire the selection changed event with the terminal text! + * to the registered listeners. + * see also TerminalControlSelectionListener- mouseUp + * + * @since 4.1 + */ + protected void fireTerminalSelectionChanged() { + updateStatusLine(); + CTabItem item = getActiveTabItem(); + if (item != null && !item.isDisposed()) { + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal != null && !terminal.isDisposed()) { + fireSelectionChanged(new StructuredSelection(terminal.getSelection())); + } + } + } + + /** + * Fire the selection changed event to the registered listeners. + */ + protected final void fireSelectionChanged(ISelection selection) { + // Create the selection changed event + SelectionChangedEvent event = new SelectionChangedEvent(TabFolderManager.this, selection); + + // First, invoke the registered listeners and let them do their job + for (ISelectionChangedListener listener : selectionChangedListeners) { + listener.selectionChanged(event); + } + } + + /** + * Update the parent view status line. + */ + public final void updateStatusLine() { + String message = null; + IStatusLineManager manager = parentView.getViewSite().getActionBars().getStatusLineManager(); + + CTabItem item = getActiveTabItem(); + if (item != null && !item.isDisposed()) { + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + if (terminal != null && !terminal.isDisposed()) { + StringBuilder buffer = new StringBuilder(); + + buffer.append(state2msg(item, terminal.getState())); + buffer.append(" - "); //$NON-NLS-1$ + + String encoding = terminal.getEncoding(); + if (encoding == null || "ISO-8859-1".equals(encoding)) { //$NON-NLS-1$ + encoding = "Default (ISO-8859-1)"; //$NON-NLS-1$ + } + buffer.append(NLS.bind(Messages.TabFolderManager_encoding, encoding)); + + message = buffer.toString(); + } + } + + manager.setMessage(message); + } + + /** + * Returns the string representation of the given terminal state. + * + * @param item The tab folder item. Must not be null. + * @param state The terminal state. Must not be null. + * + * @return The string representation. + */ + @SuppressWarnings("unchecked") + protected String state2msg(CTabItem item, TerminalState state) { + Assert.isNotNull(item); + Assert.isNotNull(state); + + // Determine the terminal properties of the tab folder + Map properties = (Map)item.getData("properties"); //$NON-NLS-1$ + + // Get he current terminal state as string + String stateStr = state.toString(); + // Lookup a matching text representation of the state + String key = "TabFolderManager_state_" + stateStr.replaceAll("\\.", " ").trim().toLowerCase(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + String stateMsg = null; + if (properties != null) stateMsg = properties.get(key) instanceof String ? (String) properties.get(key) : null; + if (stateMsg == null) stateMsg = Messages.getString(key); + if (stateMsg == null) stateMsg = stateStr; + + return stateMsg; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderMenuHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderMenuHandler.java new file mode 100644 index 00000000000..39c4e465e0b --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderMenuHandler.java @@ -0,0 +1,400 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.action.IContributionItem; +import org.eclipse.jface.action.IMenuListener2; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.TextTransfer; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionClearAll; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionCopy; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionPaste; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionSelectAll; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.actions.SelectEncodingAction; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.ui.IWorkbenchActionConstants; + +/** + * Terminal tab folder menu handler. + */ +public class TabFolderMenuHandler extends PlatformObject { + // Reference to the parent terminals console view + private final ITerminalsView parentView; + // Reference to the tab folder context menu manager + private MenuManager contextMenuManager; + // Reference to the tab folder context menu + private Menu contextMenu; + // The list of actions available within the context menu + private final List contextMenuActions = new ArrayList(); + + // The list of invalid context menu contributions "startsWith" expressions + /* default */ static final String[] INVALID_CONTRIBUTIONS_STARTS_WITH = { + "org.eclipse.cdt", "org.eclipse.ui.edit" //$NON-NLS-1$ //$NON-NLS-2$ + }; + + /** + * Default menu listener implementation. + */ + protected class MenuListener implements IMenuListener2 { + + /* (non-Javadoc) + * @see org.eclipse.jface.action.IMenuListener2#menuAboutToHide(org.eclipse.jface.action.IMenuManager) + */ + @Override + public void menuAboutToHide(IMenuManager manager) { + // CQ:WIND00192293 and CQ:WIND194204 - don't update actions on menuAboutToHide + // See also http://bugs.eclipse.org/296212 + // updateMenuItems(false); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.action.IMenuListener#menuAboutToShow(org.eclipse.jface.action.IMenuManager) + */ + @Override + public void menuAboutToShow(IMenuManager manager) { + removeInvalidContributions(manager); + updateMenuItems(true); + } + + /** + * Bug 392249: Remove contributions that appear in the context in Eclipse 4.x which are + * not visible in Eclipse 3.8.x. Re-evaluate from time to time! + * + * @param manager The menu manager or null + */ + private void removeInvalidContributions(IMenuManager manager) { + if (manager == null) return; + + IContributionItem[] items = manager.getItems(); + for (IContributionItem item : items) { + String id = item.getId(); + if (id != null) { + for (String prefix : INVALID_CONTRIBUTIONS_STARTS_WITH) { + if (id.startsWith(prefix)) { + manager.remove(item); + break; + } + } + } + } + } + } + + /** + * Constructor. + * + * @param parentView The parent terminals console view. Must not be null. + */ + public TabFolderMenuHandler(ITerminalsView parentView) { + super(); + Assert.isNotNull(parentView); + this.parentView = parentView; + } + + /** + * Returns the parent terminals console view. + * + * @return The parent terminals console view instance. + */ + protected final ITerminalsView getParentView() { + return parentView; + } + + /** + * Returns the tab folder associated with the parent view. + * + * @return The tab folder or null. + */ + @SuppressWarnings("cast") + protected final CTabFolder getTabFolder() { + return (CTabFolder) getParentView().getAdapter(CTabFolder.class); + } + + /** + * Dispose the tab folder menu handler instance. + */ + public void dispose() { + // Dispose the context menu + if (contextMenu != null) { contextMenu.dispose(); contextMenu = null; } + // Dispose the context menu manager + if (contextMenuManager != null) { contextMenuManager.dispose(); contextMenuManager = null; } + // Clear all actions + contextMenuActions.clear(); + } + + /** + * Setup the context menu for the tab folder. The method will return + * immediately if the menu handler had been initialized before. + * + * @param tabFolder The tab folder control. Must not be null. + */ + public void initialize() { + // Return immediately if the menu manager and menu got initialized already + if (contextMenuManager != null && contextMenu != null) { + return; + } + + // Get the tab folder + CTabFolder tabFolder = getTabFolder(); + if (tabFolder == null) { + return; + } + + // Create the menu manager if not done before + contextMenuManager = new MenuManager("#PopupMenu"); //$NON-NLS-1$ + + // Bug 392249: Register our menu listener after registering the context menu + // for contributions. That way we can use our menu listener to get + // rid of unwanted/misguided contributions. At least until this is + // fixed in the Eclipse 4.x platform. + + // Create the context menu + contextMenu = contextMenuManager.createContextMenu(tabFolder); + // Temporarily set the menu on the tab folder to avoid the case + // where the menu has a different parent shell than the control. + // This can be the case if the tab folder is re-parented to the + // "PartRenderingEngine's limbo". + tabFolder.setMenu(contextMenu); + + // Create the context menu action instances + doCreateContextMenuActions(); + + // Fill the context menu + doFillContextMenu(contextMenuManager); + + // Register to the view site to open the menu for contributions + getParentView().getSite().registerContextMenu(contextMenuManager, getParentView().getSite().getSelectionProvider()); + + // Create and associated the menu listener + contextMenuManager.addMenuListener(new MenuListener()); + } + + /** + * Adds the given action to the context menu actions list. + * + * @param action The action instance. Must not be null. + */ + protected final void add(AbstractTerminalAction action) { + Assert.isNotNull(action); + contextMenuActions.add(action); + } + + /** + * Create the context menu actions. + */ + @SuppressWarnings("cast") + protected void doCreateContextMenuActions() { + // Create and add the copy action + add(new TerminalActionCopy() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the paste action + add(new TerminalActionPaste() { + @SuppressWarnings({ "unchecked" }) + @Override + public void run() { + // Determine if pasting to the active tab require backslash translation + boolean needsTranslation = false; + + TabFolderManager manager = (TabFolderManager) getParentView().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + Map properties = (Map)activeTabItem.getData("properties"); //$NON-NLS-1$ + if (properties != null && properties.containsKey(ITerminalsConnectorConstants.PROP_TRANSLATE_BACKSLASHES_ON_PASTE)) { + Object value = properties.get(ITerminalsConnectorConstants.PROP_TRANSLATE_BACKSLASHES_ON_PASTE); + needsTranslation = value instanceof Boolean ? ((Boolean)value).booleanValue() : false; + } + } + } + + if (needsTranslation) { + ITerminalViewControl target = getTarget(); + if (target != null && target.getClipboard() != null && !target.getClipboard().isDisposed()) { + String text = (String) target.getClipboard().getContents(TextTransfer.getInstance()); + if (text != null) { + text = text.replace('\\', '/'); + + Object[] data = new Object[] { text }; + Transfer[] types = new Transfer[] { TextTransfer.getInstance() }; + target.getClipboard().setContents(data, types, DND.CLIPBOARD); + } + } + } + + super.run(); + } + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the clear all action + add(new TerminalActionClearAll() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.TerminalActionPaste#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + super.updateAction(aboutToShow); + if (getTarget() != null && getTarget().getState() != TerminalState.CONNECTED) { + setEnabled(false); + } + } + }); + + // Create and add the select all action + add(new TerminalActionSelectAll() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the select encoding action + add (new SelectEncodingAction((TabFolderManager) getParentView().getAdapter(TabFolderManager.class)) { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + } + + /** + * Returns the currently active terminal control. + * + * @return The currently active terminal control or null. + */ + @SuppressWarnings("cast") + protected ITerminalViewControl getActiveTerminalViewControl() { + ITerminalViewControl terminal = null; + + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager) getParentView().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null) { + terminal = (ITerminalViewControl)activeTabItem.getData(); + } + } + + return terminal; + } + + /** + * Fill in the context menu content within the given manager. + * + * @param manager The menu manager. Must not be null. + */ + protected void doFillContextMenu(MenuManager manager) { + Assert.isNotNull(manager); + + // Loop all actions and add them to the menu manager + for (AbstractTerminalAction action : contextMenuActions) { + manager.add(action); + // Add a separator after the paste action + if (action instanceof TerminalActionPaste) { + manager.add(new Separator()); + } + // Add a separator after the select all action + if (action instanceof TerminalActionSelectAll) { + manager.add(new Separator()); + } + } + + // Menu contributions will end up here + manager.add(new Separator()); + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + } + + /** + * Update the context menu items on showing or hiding the context menu. + * + * @param aboutToShow True if the menu is about to show, false otherwise. + */ + protected void updateMenuItems(boolean aboutToShow) { + // Loop all actions and update the status + for (AbstractTerminalAction action : contextMenuActions) { + action.updateAction(aboutToShow); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Object getAdapter(Class adapter) { + if (MenuManager.class.isAssignableFrom(adapter)) { + return contextMenuManager; + } else if (Menu.class.isAssignableFrom(adapter)) { + if (contextMenu == null || contextMenu.isDisposed()) { + contextMenu = contextMenuManager.createContextMenu(getTabFolder()); + } + // Clear the menu from the tab folder now - see initialize() + getTabFolder().setMenu(null); + return contextMenu; + } + + // Try the parent view + Object adapted = getParentView().getAdapter(adapter); + if (adapted != null) { + return adapted; + } + + return super.getAdapter(adapter); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderSelectionListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderSelectionListener.java new file mode 100644 index 00000000000..6ac1b5560cd --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderSelectionListener.java @@ -0,0 +1,57 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.events.SelectionListener; + +/** + * Terminal tab folder default selection listener implementation. + */ +public class TabFolderSelectionListener implements SelectionListener { + private final TabFolderManager parentTabFolderManager; + + /** + * Constructor. + * + * @param parentTabFolderManager The parent tab folder manager. Must not be null + */ + public TabFolderSelectionListener(TabFolderManager parentTabFolderManager) { + Assert.isNotNull(parentTabFolderManager); + this.parentTabFolderManager = parentTabFolderManager; + } + + /** + * Returns the parent terminal console tab folder manager instance. + * + * @return The parent terminal console tab folder manager instance. + */ + protected final TabFolderManager getParentTabFolderManager() { + return parentTabFolderManager; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetDefaultSelected(SelectionEvent e) { + } + + /* (non-Javadoc) + * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) + */ + @Override + public void widgetSelected(SelectionEvent e) { + parentTabFolderManager.fireSelectionChanged(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderToolbarHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderToolbarHandler.java new file mode 100644 index 00000000000..017a87c1122 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabFolderToolbarHandler.java @@ -0,0 +1,375 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.PlatformObject; +import org.eclipse.jface.action.IToolBarManager; +import org.eclipse.jface.action.Separator; +import org.eclipse.jface.viewers.ISelectionChangedListener; +import org.eclipse.jface.viewers.SelectionChangedEvent; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionClearAll; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionCopy; +import org.eclipse.tm.internal.terminal.control.actions.TerminalActionPaste; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.ui.actions.AbstractAction; +import org.eclipse.tm.terminal.view.ui.actions.NewTerminalViewAction; +import org.eclipse.tm.terminal.view.ui.actions.TabScrollLockAction; +import org.eclipse.tm.terminal.view.ui.actions.ToggleCommandFieldAction; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.ui.IActionBars; +import org.eclipse.ui.IWorkbenchActionConstants; + + +/** + * Terminal tab folder toolbar handler. + */ +public class TabFolderToolbarHandler extends PlatformObject { + // Reference to the parent terminals console view + private final ITerminalsView parentView; + // Reference to the toolbar manager + private IToolBarManager toolbarManager; + // Reference to the selection listener + private ToolbarSelectionChangedListener selectionChangedListener; + // The list of actions available within the toolbar + private final List toolbarActions = new ArrayList(); + + /** + * Default selection listener implementation. + */ + protected class ToolbarSelectionChangedListener implements ISelectionChangedListener { + + /* (non-Javadoc) + * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) + */ + @Override + public void selectionChanged(SelectionChangedEvent event) { + boolean enable = event != null; + + // The VlmConsoleTabFolderManager is listening to the selection changes of the + // TabFolder and fires selection changed events. + if (enable && event.getSource() instanceof TabFolderManager) { + enable = event.getSelection() instanceof StructuredSelection + && !event.getSelection().isEmpty() + && (((StructuredSelection)event.getSelection()).getFirstElement() instanceof CTabItem + || ((StructuredSelection)event.getSelection()).getFirstElement() instanceof String); + } + + updateToolbarItems(enable); + } + } + + /** + * Constructor. + * + * @param parentView The parent terminals console view. Must not be null. + */ + public TabFolderToolbarHandler(ITerminalsView parentView) { + super(); + Assert.isNotNull(parentView); + this.parentView = parentView; + } + + /** + * Returns the parent terminals console view. + * + * @return The terminals console view instance. + */ + protected final ITerminalsView getParentView() { + return parentView; + } + + /** + * Returns the tab folder associated with the parent view. + * + * @return The tab folder or null. + */ + @SuppressWarnings("cast") + protected final CTabFolder getTabFolder() { + return (CTabFolder) getParentView().getAdapter(CTabFolder.class); + } + + /** + * Returns the currently active terminal control. + * + * @return The currently active terminal control or null. + */ + @SuppressWarnings("cast") + public ITerminalViewControl getActiveTerminalViewControl() { + ITerminalViewControl terminal = null; + + // Get the active tab item from the tab folder manager + TabFolderManager manager = (TabFolderManager) getParentView().getAdapter(TabFolderManager.class); + if (manager != null) { + // If we have the active tab item, we can get the active terminal control + CTabItem activeTabItem = manager.getActiveTabItem(); + if (activeTabItem != null && !activeTabItem.isDisposed()) { + terminal = (ITerminalViewControl)activeTabItem.getData(); + } + } + + return terminal; + } + + /** + * Dispose the tab folder menu handler instance. + */ + public void dispose() { + // Dispose the selection changed listener + if (selectionChangedListener != null) { + getParentView().getViewSite().getSelectionProvider().removeSelectionChangedListener(selectionChangedListener); + selectionChangedListener = null; + } + + // Clear all actions + toolbarActions.clear(); + } + + /** + * Setup the context menu for the tab folder. The method will return + * immediately if the toolbar handler had been initialized before. + * + * @param tabFolder The tab folder control. Must not be null. + */ + public void initialize() { + // Return immediately if the toolbar manager got initialized already + if (toolbarManager != null) { + return; + } + + // Register ourself as selection listener to the tab folder + selectionChangedListener = doCreateSelectionChangedListener(); + Assert.isNotNull(selectionChangedListener); + getParentView().getViewSite().getSelectionProvider().addSelectionChangedListener(selectionChangedListener); + + // Get the parent view action bars + IActionBars bars = getParentView().getViewSite().getActionBars(); + + // From the action bars, get the toolbar manager + toolbarManager = bars.getToolBarManager(); + + // Create the toolbar action instances + doCreateToolbarActions(); + + // Fill the toolbar + doFillToolbar(toolbarManager); + + // Update actions + updateToolbarItems(false); + } + + /** + * Creates a new selection changed listener instance. + * + * @return The new selection changed listener instance. + */ + protected ToolbarSelectionChangedListener doCreateSelectionChangedListener() { + return new ToolbarSelectionChangedListener(); + } + + /** + * Adds the given action to the toolbar actions list. + * + * @param action The action instance. Must not be null. + */ + protected final void add(AbstractTerminalAction action) { + Assert.isNotNull(action); + toolbarActions.add(action); + } + + /** + * Removes the given action from the toolbar actions list. + * + * @param action The action instance. Must not be null. + */ + protected final void remove(AbstractTerminalAction action) { + Assert.isNotNull(action); + toolbarActions.remove(action); + } + + /** + * Create the toolbar actions. + */ + protected void doCreateToolbarActions() { + // Create and add the paste action + add(new TerminalActionPaste() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the copy action + add(new TerminalActionCopy() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the scroll lock action + add (new TabScrollLockAction() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the clear all action + add(new TerminalActionClearAll() { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.TerminalActionPaste#updateAction(boolean) + */ + @Override + public void updateAction(boolean aboutToShow) { + super.updateAction(aboutToShow); + if (getTarget() != null && getTarget().getState() != TerminalState.CONNECTED) { + setEnabled(false); + } + } + }); + + // Create and add the toggle command input field action + add (new ToggleCommandFieldAction(getParentView()) { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + + // Create and add the new terminal view action + add (new NewTerminalViewAction(getParentView()) { + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction#getTarget() + */ + @Override + protected ITerminalViewControl getTarget() { + return getActiveTerminalViewControl(); + } + }); + } + + /** + * Fill in the context menu content within the given manager. + * + * @param manager The menu manager. Must not be null. + */ + protected void doFillToolbar(IToolBarManager manager) { + Assert.isNotNull(manager); + + // Note: For the toolbar, the actions are added from left to right! + // So we start with the additions marker here which is the most + // left contribution item. + manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); + manager.add(new Separator("anchor")); //$NON-NLS-1$ + + // we want that at the end + NewTerminalViewAction newTerminalAction = null; + + // Loop all actions and add them to the menu manager + for (AbstractTerminalAction action : toolbarActions) { + // Add a separator before the clear all action or if the action is a separator + if (action instanceof TabScrollLockAction + || (action instanceof AbstractAction && ((AbstractAction)action).isSeparator())) { + manager.insertAfter("anchor", new Separator()); //$NON-NLS-1$ + } + // skip new terminal view action for now + if (action instanceof NewTerminalViewAction){ + newTerminalAction = (NewTerminalViewAction)action; + continue; + } + // Add the action itself + manager.insertAfter("anchor", action); //$NON-NLS-1$ + } + // now add to the end + if (newTerminalAction != null){ + manager.add(newTerminalAction); + } + } + + /** + * Update the toolbar items. + * + * @param enabled True if the items shall be enabled, false otherwise. + */ + protected void updateToolbarItems(boolean enabled) { + // Determine the currently active terminal control + ITerminalViewControl control = getActiveTerminalViewControl(); + // Loop all actions and update the status + for (AbstractTerminalAction action : toolbarActions) { + // If the terminal control is not available, the updateAction + // method of certain actions enable the action (bugzilla #260372). + // Workaround by forcing the action to get disabled with setEnabled. + if (control == null && !(action instanceof NewTerminalViewAction)) { + action.setEnabled(false); + } + else { + action.updateAction(enabled); + } + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Object getAdapter(Class adapter) { + if (IToolBarManager.class.isAssignableFrom(adapter)) { + return toolbarManager; + } + + // Try the toolbar actions + for (AbstractTerminalAction action : toolbarActions) { + if (adapter.isAssignableFrom(action.getClass())) { + return action; + } + } + + // Try the parent view + Object adapted = getParentView().getAdapter(adapter); + if (adapted != null) { + return adapted; + } + + return super.getAdapter(adapter); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabTerminalListener.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabTerminalListener.java new file mode 100644 index 00000000000..3dd5cb784d0 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/tabs/TabTerminalListener.java @@ -0,0 +1,162 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.tabs; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.jface.viewers.ISelectionProvider; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.widgets.Display; +import org.eclipse.tm.internal.terminal.control.ITerminalListener2; +import org.eclipse.tm.internal.terminal.provisional.api.TerminalState; +import org.eclipse.tm.terminal.view.ui.nls.Messages; + +/** + * Terminal tab default terminal listener implementation. + */ +public class TabTerminalListener implements ITerminalListener2 { + private static final String TAB_TERMINAL_LISTENER = "TabTerminalListener"; //$NON-NLS-1$ + /* default */ final TabFolderManager tabFolderManager; + private CTabItem tabItem; + private final String tabItemTitle; + + /** + * Move a TabTerminalListener instance to another item (for DnD). + * + * @param fromItem item to detach the listener from + * @param toItem item to attach listener to + */ + static void move(CTabItem fromItem, CTabItem toItem) { + TabTerminalListener listener = (TabTerminalListener) fromItem.getData(TAB_TERMINAL_LISTENER); + if (listener != null) { + listener.attachTo(toItem); + } + } + + /** + * Constructor. + * + * @param tabFolderManager The parent tab folder manager. Must not be null. + * @param tabItem The parent tab item. Must not be null. + */ + public TabTerminalListener(TabFolderManager tabFolderManager, CTabItem tabItem) { + super(); + Assert.isNotNull(tabFolderManager); + Assert.isNotNull(tabItem); + this.tabFolderManager = tabFolderManager; + // Remember the original tab item title + tabItemTitle = tabItem.getText(); + + attachTo(tabItem); + } + + private void attachTo(CTabItem item) { + if (tabItem != null) tabItem.setData(TAB_TERMINAL_LISTENER, null); + item.setData(TAB_TERMINAL_LISTENER, this); + tabItem = item; + } + + /** + * Returns the associated parent tab item. + * + * @return The parent tab item. + */ + protected final CTabItem getTabItem() { + return tabItem; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalListener#setState(org.eclipse.tm.internal.terminal.provisional.api.TerminalState) + */ + @Override + public void setState(final TerminalState state) { + // The tab item must have been not yet disposed + final CTabItem item = getTabItem(); + if (item == null || item.isDisposed()) return; + + // Run asynchronously in the display thread + item.getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + // Update the tab item title + String newTitle = getTerminalConsoleTabTitle(state); + if (newTitle != null) item.setText(newTitle); + + // Turn off the command field (if necessary) + TabCommandFieldHandler handler = tabFolderManager.getTabCommandFieldHandler(item); + if (TerminalState.CLOSED.equals(state) && handler != null && handler.hasCommandInputField()) { + handler.setCommandInputField(false); + // Trigger a selection changed event to update the action enablements + // and the status line + ISelectionProvider provider = tabFolderManager.getParentView().getViewSite().getSelectionProvider(); + Assert.isNotNull(provider); + provider.setSelection(provider.getSelection()); + } else { + // Update the status line + tabFolderManager.updateStatusLine(); + } + } + }); + } + + /** + * Returns the title to set to the terminal console tab for the given state. + *

              + * Note: This method is called from {@link #setState(TerminalState)} and + * is expected to by called within the UI thread. + * + * @param state The terminal state. Must not be null. + * @return The terminal console tab title to set or null to leave the title unchanged. + */ + protected String getTerminalConsoleTabTitle(TerminalState state) { + Assert.isNotNull(state); + Assert.isNotNull(Display.findDisplay(Thread.currentThread())); + + // The tab item must have been not yet disposed + CTabItem item = getTabItem(); + if (item == null || item.isDisposed()) return null; + + // Get the current tab title + String oldTitle = item.getText(); + + // Construct the new title + String newTitle = null; + + if (TerminalState.CLOSED.equals(state)) { + newTitle = NLS.bind(Messages.TabTerminalListener_consoleClosed, tabItemTitle, tabFolderManager.state2msg(item, state)); + } + else if (TerminalState.CONNECTING.equals(state)) { + newTitle = NLS.bind(Messages.TabTerminalListener_consoleConnecting, tabItemTitle, tabFolderManager.state2msg(item, state)); + } + else if (TerminalState.CONNECTED.equals(state)) { + newTitle = tabItemTitle; + } + + return newTitle != null && !newTitle.equals(oldTitle) ? newTitle : null; + } + + /* (non-Javadoc) + * @see org.eclipse.tm.internal.terminal.control.ITerminalListener#setTerminalTitle(java.lang.String) + */ + @Override + public void setTerminalTitle(String title) { + } + + /** + * @see org.eclipse.tm.internal.terminal.control.ITerminalListener2#setTerminalSelectionChanged() + * @since 4.1 + */ + @Override + public void setTerminalSelectionChanged() { + tabFolderManager.fireTerminalSelectionChanged(); + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/OldTerminalsViewHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/OldTerminalsViewHandler.java new file mode 100644 index 00000000000..bc02c4ad931 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/OldTerminalsViewHandler.java @@ -0,0 +1,126 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.view; + +import org.eclipse.swt.widgets.Composite; +import org.eclipse.tm.terminal.view.ui.interfaces.IUIConstants; +import org.eclipse.ui.IPartListener2; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.IWorkbenchPart; +import org.eclipse.ui.IWorkbenchPartReference; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.part.ViewPart; + +/** + * Old terminals view handler implementation. + *

              + * If invoked, the view implementation opens the new terminals view and + * closes itself afterwards. + */ +public class OldTerminalsViewHandler extends ViewPart { + + boolean fReplaced; + IPartListener2 fPartlistener; + + /** + * Constructor. + */ + public OldTerminalsViewHandler() { + super(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createPartControl(Composite parent) { + replaceWithTerminalsView(); + } + + protected void replaceWithTerminalsView() { + if (fReplaced) + return; + IViewSite site = getViewSite(); + final IWorkbenchPage page = site.getPage(); + + site.getShell().getDisplay().asyncExec(new Runnable() { + @Override + public void run() { + if (fReplaced) + return; + if (!page.isPageZoomed() || page.getActivePart() instanceof TerminalsView) { + fReplaced = true; + // Show the new view + try { + page.showView(IUIConstants.ID, null, IWorkbenchPage.VIEW_CREATE); + } + catch (PartInitException e) { /* ignored on purpose */ } + + // Hide ourself in the current perspective + page.hideView(OldTerminalsViewHandler.this); + } else if (fPartlistener == null) { + final IWorkbenchPart maximizedPart = page.getActivePart(); + page.addPartListener(fPartlistener = new IPartListener2() { + @Override + public void partVisible(IWorkbenchPartReference partRef) { + if (partRef.getPart(false) == OldTerminalsViewHandler.this) { + page.removePartListener(this); + fPartlistener = null; + replaceWithTerminalsView(); + } + } + @Override + public void partOpened(IWorkbenchPartReference partRef) { + } + @Override + public void partInputChanged(IWorkbenchPartReference partRef) { + } + @Override + public void partHidden(IWorkbenchPartReference partRef) { + } + @Override + public void partDeactivated(IWorkbenchPartReference partRef) { + } + @Override + public void partClosed(IWorkbenchPartReference partRef) { + if (partRef.getPart(false) == OldTerminalsViewHandler.this) { + page.removePartListener(this); + fPartlistener = null; + } else if (partRef.getPart(false) == maximizedPart) { + page.removePartListener(this); + fPartlistener = null; + replaceWithTerminalsView(); + } + } + @Override + public void partBroughtToTop(IWorkbenchPartReference partRef) { + } + @Override + public void partActivated(IWorkbenchPartReference partRef) { + } + }); + } + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#setFocus() + */ + @Override + public void setFocus() { + // should not happen, but just in case - replace on focus + replaceWithTerminalsView(); + } + +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/TerminalsView.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/TerminalsView.java new file mode 100644 index 00000000000..d66fd3cf036 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/TerminalsView.java @@ -0,0 +1,780 @@ +/******************************************************************************* + * Copyright (c) 2011, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + * Max Weninger (Wind River) - [361363] [TERMINALS] Implement "Pin&Clone" for the "Terminals" view + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.view; + +import java.io.File; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; + +import org.eclipse.core.commands.Command; +import org.eclipse.core.commands.ParameterizedCommand; +import org.eclipse.core.expressions.EvaluationContext; +import org.eclipse.core.expressions.IEvaluationContext; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.IStatus; +import org.eclipse.core.runtime.Platform; +import org.eclipse.core.runtime.Status; +import org.eclipse.jface.resource.JFaceResources; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.IStructuredSelection; +import org.eclipse.jface.viewers.StructuredSelection; +import org.eclipse.swt.SWT; +import org.eclipse.swt.custom.CTabFolder; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.swt.dnd.ByteArrayTransfer; +import org.eclipse.swt.dnd.DND; +import org.eclipse.swt.dnd.DragSource; +import org.eclipse.swt.dnd.DragSourceEvent; +import org.eclipse.swt.dnd.DragSourceListener; +import org.eclipse.swt.dnd.DropTarget; +import org.eclipse.swt.dnd.DropTargetEvent; +import org.eclipse.swt.dnd.DropTargetListener; +import org.eclipse.swt.dnd.Transfer; +import org.eclipse.swt.dnd.TransferData; +import org.eclipse.swt.events.DisposeListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Event; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.tm.terminal.view.ui.activator.UIPlugin; +import org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView; +import org.eclipse.tm.terminal.view.ui.nls.Messages; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderManager; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderMenuHandler; +import org.eclipse.tm.terminal.view.ui.tabs.TabFolderToolbarHandler; +import org.eclipse.tm.terminal.view.ui.view.showin.GitShowInContextHandler; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.ISources; +import org.eclipse.ui.IViewSite; +import org.eclipse.ui.IWorkbenchPreferenceConstants; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.commands.ICommandService; +import org.eclipse.ui.handlers.IHandlerService; +import org.eclipse.ui.part.IShowInTarget; +import org.eclipse.ui.part.PageBook; +import org.eclipse.ui.part.ShowInContext; +import org.eclipse.ui.part.ViewPart; +import org.osgi.framework.Bundle; + +/** + * Terminal view. + */ +public class TerminalsView extends ViewPart implements ITerminalsView, IShowInTarget { + + // Reference to the main page book control + private PageBook pageBookControl; + // Reference to the tab folder maintaining the consoles + /* default */ CTabFolder tabFolderControl; + // Reference to the tab folder manager + /* default */ TabFolderManager tabFolderManager; + // Reference to the tab folder menu handler + private TabFolderMenuHandler tabFolderMenuHandler; + // Reference to the tab folder toolbar handler + private TabFolderToolbarHandler tabFolderToolbarHandler; + // Reference to the empty page control (to be show if no console is open) + private Control emptyPageControl; + // The view's memento handler + private final TerminalsViewMementoHandler mementoHandler = new TerminalsViewMementoHandler(); + + /** + * "dummy" transfer just to store the information needed for the DnD + * + */ + private static class TerminalTransfer extends ByteArrayTransfer { + // The static terminal transfer type name. Unique per terminals view instance. + private static final String TYPE_NAME = "terminal-transfer-format:" + UUID.randomUUID().toString(); //$NON-NLS-1$ + // Register the type name and remember the associated unique type id. + private static final int TYPEID = registerType(TYPE_NAME); + + private CTabItem draggedFolderItem; + private TabFolderManager draggedTabFolderManager; + + /* + * Thread save singleton instance creation. + */ + private static class LazyInstanceHolder { + public static TerminalTransfer instance = new TerminalTransfer(); + } + + /** + * Constructor. + */ + TerminalTransfer() { + } + + /** + * Returns the singleton terminal transfer instance. + * @return + */ + public static TerminalTransfer getInstance() { + return LazyInstanceHolder.instance; + } + + /** + * Sets the dragged folder item. + * + * @param tabFolderItem The dragged folder item or null. + */ + public void setDraggedFolderItem(CTabItem tabFolderItem) { + draggedFolderItem = tabFolderItem; + } + + /** + * Returns the dragged folder item. + * + * @return The dragged folder item or null. + */ + public CTabItem getDraggedFolderItem() { + return draggedFolderItem; + } + + /** + * Sets the tab folder manager the associated folder item is dragged from. + * + * @param tabFolderManager The tab folder manager or null. + */ + public void setTabFolderManager(TabFolderManager tabFolderManager) { + draggedTabFolderManager = tabFolderManager; + } + + /** + * Returns the tab folder manager the associated folder item is dragged from. + * + * @return The tab folder manager or null. + */ + public TabFolderManager getTabFolderManager() { + return draggedTabFolderManager; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.dnd.Transfer#getTypeIds() + */ + @Override + protected int[] getTypeIds() { + return new int[] { TYPEID }; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.dnd.Transfer#getTypeNames() + */ + @Override + protected String[] getTypeNames() { + return new String[] { TYPE_NAME }; + } + + /* (non-Javadoc) + * @see org.eclipse.swt.dnd.ByteArrayTransfer#javaToNative(java.lang.Object, org.eclipse.swt.dnd.TransferData) + */ + @Override + public void javaToNative(Object data, TransferData transferData) { + } + + /* (non-Javadoc) + * @see org.eclipse.swt.dnd.ByteArrayTransfer#nativeToJava(org.eclipse.swt.dnd.TransferData) + */ + @Override + public Object nativeToJava(TransferData transferData) { + return null; + } + } + + /** + * Constructor. + */ + public TerminalsView() { + super(); + } + + /** + * Initialize the drag support. + */ + private void addDragSupport() { + // The event listener is registered as filter. It will receive events from all widgets. + PlatformUI.getWorkbench().getDisplay().addFilter(SWT.DragDetect, new Listener() { + /* (non-Javadoc) + * @see org.eclipse.swt.widgets.Listener#handleEvent(org.eclipse.swt.widgets.Event) + */ + @Override + public void handleEvent(Event event) { + // Only handle events where a CTabFolder is the source + if (!(event.widget instanceof CTabFolder)) return; + // TabFolderManager must be created + if (tabFolderManager == null) return; + + // only for own tab folders + if (event.widget != tabFolderControl) return; + + // Skip drag if DnD is still ongoing (bug 443787) + if (tabFolderControl.getData(DND.DRAG_SOURCE_KEY) != null) return; + + final CTabFolder draggedFolder = (CTabFolder) event.widget; + + int operations = DND.DROP_MOVE | DND.DROP_DEFAULT; + final DragSource dragSource = new DragSource(draggedFolder, operations); + + // Initialize the terminal transfer type data + TerminalTransfer.getInstance().setDraggedFolderItem(tabFolderManager.getActiveTabItem()); + TerminalTransfer.getInstance().setTabFolderManager(tabFolderManager); + + Transfer[] transferTypes = new Transfer[] { TerminalTransfer.getInstance() }; + dragSource.setTransfer(transferTypes); + + // Add a drag source listener to cleanup after the drag operation finished + dragSource.addDragListener(new DragSourceListener() { + @Override + public void dragStart(DragSourceEvent event) { + } + + @Override + public void dragSetData(DragSourceEvent event) { + } + + @Override + public void dragFinished(DragSourceEvent event) { + // dispose this drag-source-listener by disposing its drag-source + dragSource.dispose(); + + // Inhibit the action of CTabFolder's default DragDetect-listeners, + // fire a mouse-click event on the widget that was dragged. + draggedFolder.notifyListeners(SWT.MouseUp, null); + } + }); + } + }); + } + + /** + * Initialize the drop support on the terminals page book control. + */ + private void addDropSupport() { + int operations = DND.DROP_MOVE | DND.DROP_DEFAULT; + final DropTarget target = new DropTarget(pageBookControl, operations); + + Transfer[] transferTypes = new Transfer[] { TerminalTransfer.getInstance() }; + target.setTransfer(transferTypes); + + target.addDropListener(new DropTargetListener() { + @Override + public void dragEnter(DropTargetEvent event) { + // only if the drop target is different then the drag source + if (TerminalTransfer.getInstance().getTabFolderManager() == tabFolderManager) { + event.detail = DND.DROP_NONE; + } + else { + event.detail = DND.DROP_MOVE; + } + } + + @Override + public void dragOver(DropTargetEvent event) { + } + + @Override + public void dragOperationChanged(DropTargetEvent event) { + } + + @Override + public void dragLeave(DropTargetEvent event) { + } + + @Override + public void dropAccept(DropTargetEvent event) { + } + + @Override + public void drop(DropTargetEvent event) { + if (TerminalTransfer.getInstance().getDraggedFolderItem() != null && tabFolderManager != null) { + CTabItem draggedItem = TerminalTransfer.getInstance().getDraggedFolderItem(); + + CTabItem item = tabFolderManager.cloneTabItemAfterDrop(draggedItem); + tabFolderManager.bringToTop(item); + switchToTabFolderControl(); + + // dispose tab item control + final Control control = draggedItem.getControl(); + draggedItem.setControl(null); + if (control != null) control.dispose(); + + // need to remove the dispose listener first + DisposeListener disposeListener = (DisposeListener) draggedItem.getData("disposeListener"); //$NON-NLS-1$ + draggedItem.removeDisposeListener(disposeListener); + draggedItem.dispose(); + + // make sure the "new" terminals view has the focus after dragging a terminal + setFocus(); + } + } + }); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#dispose() + */ + @Override + public void dispose() { + // Dispose the tab folder manager + if (tabFolderManager != null) { + tabFolderManager.dispose(); + tabFolderManager = null; + } + // Dispose the tab folder menu handler + if (tabFolderMenuHandler != null) { + tabFolderMenuHandler.dispose(); + tabFolderMenuHandler = null; + } + // Dispose the tab folder toolbar handler + if (tabFolderToolbarHandler != null) { + tabFolderToolbarHandler.dispose(); + tabFolderToolbarHandler = null; + } + + super.dispose(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.ViewPart#init(org.eclipse.ui.IViewSite, org.eclipse.ui.IMemento) + */ + @Override + public void init(IViewSite site, IMemento memento) throws PartInitException { + super.init(site, memento); + restoreState(memento); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite) + */ + @Override + public void createPartControl(Composite parent) { + // Create the page book control + pageBookControl = doCreatePageBookControl(parent); + Assert.isNotNull(pageBookControl); + // Configure the page book control + doConfigurePageBookControl(pageBookControl); + + // Create the empty page control + emptyPageControl = doCreateEmptyPageControl(pageBookControl); + Assert.isNotNull(emptyPageControl); + // Configure the empty page control + doConfigureEmptyPageControl(emptyPageControl); + + // Create the tab folder control (empty) + tabFolderControl = doCreateTabFolderControl(pageBookControl); + Assert.isNotNull(tabFolderControl); + // Configure the tab folder control + doConfigureTabFolderControl(tabFolderControl); + + // Create the tab folder manager + tabFolderManager = doCreateTabFolderManager(this); + Assert.isNotNull(tabFolderManager); + // Set the tab folder manager as the selection provider + getSite().setSelectionProvider(tabFolderManager); + + // Setup the tab folder menu handler + tabFolderMenuHandler = doCreateTabFolderMenuHandler(this); + Assert.isNotNull(tabFolderMenuHandler); + doConfigureTabFolderMenuHandler(tabFolderMenuHandler); + + // Setup the tab folder toolbar handler + tabFolderToolbarHandler = doCreateTabFolderToolbarHandler(this); + Assert.isNotNull(tabFolderToolbarHandler); + doConfigureTabFolderToolbarHandler(tabFolderToolbarHandler); + + // Show the empty page control by default + switchToEmptyPageControl(); + + String secondaryId = ((IViewSite) getSite()).getSecondaryId(); + if (secondaryId != null) { + String defaultTitle = getPartName(); + // set title + setPartName(defaultTitle + " " + secondaryId); //$NON-NLS-1$ + } + + // Initialize DnD support + addDragSupport(); + addDropSupport(); + } + + /** + * Creates the {@link PageBook} instance. + * + * @param parent The parent composite. Must not be null. + * @return The page book instance. Must never be null. + */ + protected PageBook doCreatePageBookControl(Composite parent) { + return new PageBook(parent, SWT.NONE); + } + + /** + * Configure the given page book control. + * + * @param pagebook The page book control. Must not be null. + */ + protected void doConfigurePageBookControl(PageBook pagebook) { + Assert.isNotNull(pagebook); + + if (getContextHelpId() != null) PlatformUI.getWorkbench().getHelpSystem().setHelp(pagebook, getContextHelpId()); + } + + /** + * Returns the context help id associated with the terminals console view instance. + *

              + * Note: The default implementation returns the view id as context help id. + * + * @return The context help id or null if none is associated. + */ + @Override + public String getContextHelpId() { + return getViewSite().getId(); + } + + /** + * Creates the empty page control instance. + * + * @param parent The parent composite. Must not be null. + * @return The empty page control instance. Must never be null. + */ + protected Control doCreateEmptyPageControl(Composite parent) { + Composite composite = new Composite(parent, SWT.NONE); + composite.setLayout(new GridLayout()); + composite.setLayoutData(new GridData(GridData.FILL_BOTH)); + return composite; + } + + /** + * Configures the empty page control. + * + * @param control The empty page control. Must not be null. + */ + protected void doConfigureEmptyPageControl(Control control) { + Assert.isNotNull(control); + } + + /** + * Creates the tab folder control instance. + * + * @param parent The parent composite. Must not be null. + * @return The tab folder control instance. Must never be null. + */ + protected CTabFolder doCreateTabFolderControl(Composite parent) { + return new CTabFolder(parent, SWT.NO_REDRAW_RESIZE | SWT.NO_TRIM | SWT.FLAT | SWT.BORDER); + } + + /** + * Configures the tab folder control. + * + * @param tabFolder The tab folder control. Must not be null. + */ + protected void doConfigureTabFolderControl(final CTabFolder tabFolder) { + Assert.isNotNull(tabFolder); + + // Set the layout data + tabFolder.setLayoutData(new GridData(GridData.FILL_BOTH)); + + // Set the tab gradient coloring from the global preferences + if (useGradientTabBackgroundColor()) { + tabFolder.setSelectionBackground(new Color[] { + JFaceResources.getColorRegistry().get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_START"), //$NON-NLS-1$ + JFaceResources.getColorRegistry().get("org.eclipse.ui.workbench.ACTIVE_TAB_BG_END") //$NON-NLS-1$ + }, new int[] { 100 }, true); + } + // Apply the tab folder selection foreground color + tabFolder.setSelectionForeground(JFaceResources.getColorRegistry().get("org.eclipse.ui.workbench.ACTIVE_TAB_TEXT_COLOR")); //$NON-NLS-1$ + + // Set the tab style from the global preferences + tabFolder.setSimple(PlatformUI.getPreferenceStore().getBoolean(IWorkbenchPreferenceConstants.SHOW_TRADITIONAL_STYLE_TABS)); + + // Attach the mouse listener + tabFolder.addMouseListener(new MouseAdapter() { + @Override + public void mouseDown(MouseEvent e) { + if (e.button == 2) { + // middle mouse button click - close tab + CTabItem item = tabFolder.getItem(new Point(e.x, e.y)); + if (item != null) item.dispose(); + } + } + }); + } + + /** + * If True is returned, the inner tabs are colored with gradient coloring set in + * the Eclipse workbench color settings. + * + * @return True to use gradient tab colors, false otherwise. + */ + protected boolean useGradientTabBackgroundColor() { + return false; + } + + /** + * Creates the tab folder manager. + * + * @param parentView The parent view instance. Must not be null. + * @return The tab folder manager. Must never be null. + */ + protected TabFolderManager doCreateTabFolderManager(ITerminalsView parentView) { + Assert.isNotNull(parentView); + return new TabFolderManager(parentView); + } + + /** + * Creates the tab folder menu handler. + * + * @param parentView The parent view instance. Must not be null. + * @return The tab folder menu handler. Must never be null. + */ + protected TabFolderMenuHandler doCreateTabFolderMenuHandler(ITerminalsView parentView) { + Assert.isNotNull(parentView); + return new TabFolderMenuHandler(parentView); + } + + /** + * Configure the tab folder menu handler + * + * @param menuHandler The tab folder menu handler. Must not be null. + */ + protected void doConfigureTabFolderMenuHandler(TabFolderMenuHandler menuHandler) { + Assert.isNotNull(menuHandler); + menuHandler.initialize(); + } + + /** + * Creates the tab folder toolbar handler. + * + * @param parentView The parent view instance. Must not be null. + * @return The tab folder toolbar handler. Must never be null. + */ + protected TabFolderToolbarHandler doCreateTabFolderToolbarHandler(ITerminalsView parentView) { + Assert.isNotNull(parentView); + return new TabFolderToolbarHandler(parentView); + } + + /** + * Configure the tab folder toolbar handler + * + * @param toolbarHandler The tab folder toolbar handler. Must not be null. + */ + protected void doConfigureTabFolderToolbarHandler(TabFolderToolbarHandler toolbarHandler) { + Assert.isNotNull(toolbarHandler); + toolbarHandler.initialize(); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#setFocus() + */ + @Override + public void setFocus() { + if (pageBookControl != null) pageBookControl.setFocus(); + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView#switchToEmptyPageControl() + */ + @Override + public void switchToEmptyPageControl() { + if (pageBookControl != null && !pageBookControl.isDisposed() + && emptyPageControl != null && !emptyPageControl.isDisposed()) { + pageBookControl.showPage(emptyPageControl); + } + } + + /* (non-Javadoc) + * @see org.eclipse.tm.terminal.view.ui.interfaces.ITerminalsView#switchToTabFolderControl() + */ + @Override + public void switchToTabFolderControl() { + if (pageBookControl != null && !pageBookControl.isDisposed() + && tabFolderControl != null && !tabFolderControl.isDisposed()) { + pageBookControl.showPage(tabFolderControl); + } + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class) + */ + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Object getAdapter(Class adapter) { + if (CTabFolder.class.isAssignableFrom(adapter)) { + return tabFolderControl; + } + if (TabFolderManager.class.isAssignableFrom(adapter)) { + return tabFolderManager; + } + if (TabFolderMenuHandler.class.isAssignableFrom(adapter)) { + return tabFolderMenuHandler; + } + if (TabFolderToolbarHandler.class.isAssignableFrom(adapter)) { + return tabFolderToolbarHandler; + } + if (TerminalsViewMementoHandler.class.isAssignableFrom(adapter)) { + return mementoHandler; + } + + return super.getAdapter(adapter); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.ViewPart#saveState(org.eclipse.ui.IMemento) + */ + @Override + public void saveState(IMemento memento) { + super.saveState(memento); + if (memento == null) return; + mementoHandler.saveState(this, memento); + } + + /** + * Restore the view state from the given memento. + * + * @param memento The memento or null. + */ + public void restoreState(IMemento memento) { + if (memento == null) return; + mementoHandler.restoreState(this, memento); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.part.IShowInTarget#show(org.eclipse.ui.part.ShowInContext) + */ + @SuppressWarnings("cast") + @Override + public boolean show(ShowInContext context) { + if (context != null) { + // Get the selection from the context + ISelection selection = context.getSelection(); + + // If the selection is not set or empty, look at the input element of + // the show in context. + if (!(selection instanceof IStructuredSelection) || selection.isEmpty()) { + Object input = context.getInput(); + // If coming from the EGit repository viewer, the input element is + // org.eclipse.egit.ui.internal.history.HistoryPageInput + if ("org.eclipse.egit.ui.internal.history.HistoryPageInput".equals(input.getClass().getName())) { //$NON-NLS-1$ + Bundle bundle = Platform.getBundle("org.eclipse.egit.ui"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + selection = GitShowInContextHandler.getSelection(input); + } + } + } + + // The selection must contain elements that can be adapted to IResource, File or IPath + if (selection instanceof IStructuredSelection && !selection.isEmpty()) { + boolean isValid = true; + + // Build a new structured selection with the adapted elements + List elements = new ArrayList(); + + Iterator iterator = ((IStructuredSelection)selection).iterator(); + while (iterator.hasNext() && isValid) { + Object element = iterator.next(); + Object adapted = null; + + if (element instanceof File) { + if (!elements.contains(element)) elements.add(element); + continue; + } + adapted = element instanceof IAdaptable ? ((IAdaptable)element).getAdapter(File.class) : null; + if (adapted == null) adapted = Platform.getAdapterManager().getAdapter(element, File.class); + if (adapted == null) adapted = Platform.getAdapterManager().loadAdapter(element, File.class.getName()); + if (adapted != null) { + if (!elements.contains(adapted)) elements.add(adapted); + continue; + } + + if (element instanceof IPath) { + if (!elements.contains(element)) elements.add(element); + continue; + } + adapted = element instanceof IAdaptable ? ((IAdaptable)element).getAdapter(IPath.class) : null; + if (adapted == null) adapted = Platform.getAdapterManager().getAdapter(element, IPath.class); + if (adapted == null) adapted = Platform.getAdapterManager().loadAdapter(element, IPath.class.getName()); + if (adapted != null) { + if (!elements.contains(adapted)) elements.add(adapted); + continue; + } + + Bundle bundle = Platform.getBundle("org.eclipse.core.resources"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + if (element instanceof org.eclipse.core.resources.IResource) { + if (!elements.contains(element)) elements.add(element); + continue; + } + + adapted = element instanceof IAdaptable ? ((IAdaptable)element).getAdapter(org.eclipse.core.resources.IResource.class) : null; + if (adapted == null) adapted = Platform.getAdapterManager().getAdapter(element, org.eclipse.core.resources.IResource.class); + if (adapted == null) adapted = Platform.getAdapterManager().loadAdapter(element, org.eclipse.core.resources.IResource.class.getName()); + } + if (adapted != null) { + if (!elements.contains(adapted)) elements.add(adapted); + continue; + } + + // The EGit repository view can also set a RepositoryTreeNode (and subclasses) + // "org.eclipse.egit.ui.internal.repository.tree...." + if (element.getClass().getName().startsWith("org.eclipse.egit.ui.internal.repository.tree")) { //$NON-NLS-1$ + bundle = Platform.getBundle("org.eclipse.egit.ui"); //$NON-NLS-1$ + if (bundle != null && bundle.getState() != Bundle.UNINSTALLED && bundle.getState() != Bundle.STOPPING) { + adapted = GitShowInContextHandler.getPath(element); + } + } + if (adapted != null) { + if (!elements.contains(adapted)) elements.add(adapted); + continue; + } + + isValid = false; + } + + // If the selection is valid, fire the command to open the local terminal + if (isValid) { + selection = new StructuredSelection(elements); + ICommandService service = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class); + Command command = service != null ? service.getCommand("org.eclipse.tm.terminal.connector.local.command.launch") : null; //$NON-NLS-1$ + if (command != null && command.isDefined() && command.isEnabled()) { + try { + ParameterizedCommand pCmd = ParameterizedCommand.generateCommand(command, null); + Assert.isNotNull(pCmd); + IHandlerService handlerSvc = (IHandlerService) PlatformUI.getWorkbench().getService(IHandlerService.class); + Assert.isNotNull(handlerSvc); + IEvaluationContext ctx = handlerSvc.getCurrentState(); + ctx = new EvaluationContext(ctx, selection); + ctx.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection); + handlerSvc.executeCommandInContext(pCmd, null, ctx); + } catch (Exception e) { + // If the platform is in debug mode, we print the exception to the log view + if (Platform.inDebugMode()) { + IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(), + Messages.AbstractTriggerCommandHandler_error_executionFailed, e); + UIPlugin.getDefault().getLog().log(status); + } + } + } + return true; + } + } + } + return false; + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/TerminalsViewMementoHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/TerminalsViewMementoHandler.java new file mode 100644 index 00000000000..7fed672f369 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/TerminalsViewMementoHandler.java @@ -0,0 +1,180 @@ +/******************************************************************************* + * Copyright (c) 2012, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.view; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.eclipse.core.runtime.Assert; +import org.eclipse.swt.custom.CTabItem; +import org.eclipse.tm.internal.terminal.control.ITerminalViewControl; +import org.eclipse.tm.terminal.view.core.interfaces.constants.ITerminalsConnectorConstants; +import org.eclipse.tm.terminal.view.ui.interfaces.ILauncherDelegate; +import org.eclipse.tm.terminal.view.ui.interfaces.IMementoHandler; +import org.eclipse.tm.terminal.view.ui.launcher.LauncherDelegateManager; +import org.eclipse.ui.IMemento; +import org.eclipse.ui.PlatformUI; + +/** + * Take care of the persisted state handling of the "Terminal" view. + */ +public class TerminalsViewMementoHandler { + // The list of items to save. See the workbench listener implementation + // in o.e.tm.terminal.view.ui.activator.UIPlugin. + private final List saveables = new ArrayList(); + + /** + * Sets the list of saveable items. + * + * @param saveables The list of saveable items. Must not be null. + */ + public void setSaveables(List saveables) { + Assert.isNotNull(saveables); + this.saveables.clear(); + this.saveables.addAll(saveables); + } + + /** + * Saves the view state in the given memento. + * + * @param view The terminals view. Must not be null. + * @param memento The memento. Must not be null. + */ + @SuppressWarnings("unchecked") + public void saveState(TerminalsView view, IMemento memento) { + Assert.isNotNull(view); + Assert.isNotNull(memento); + + // Create a child element within the memento holding the + // connection info of the open, non-terminated tab items + memento = memento.createChild("terminalConnections"); //$NON-NLS-1$ + Assert.isNotNull(memento); + + // Write the view id and secondary id + memento.putString("id", view.getViewSite().getId()); //$NON-NLS-1$ + memento.putString("secondaryId", view.getViewSite().getSecondaryId()); //$NON-NLS-1$ + + // Loop the saveable items and store the connection data of each + // item to the memento + for (CTabItem item : saveables) { + // Ignore disposed items + if (item.isDisposed()) continue; + + // Get the original terminal properties associated with the tab item + Map properties = (Map)item.getData("properties"); //$NON-NLS-1$ + if (properties == null) continue; + + // Get the terminal launcher delegate + String delegateId = (String)properties.get(ITerminalsConnectorConstants.PROP_DELEGATE_ID); + ILauncherDelegate delegate = delegateId != null ? LauncherDelegateManager.getInstance().getLauncherDelegate(delegateId, false) : null; + IMementoHandler mementoHandler = delegate != null ? (IMementoHandler)delegate.getAdapter(IMementoHandler.class) : null; + if (mementoHandler != null) { + // Create terminal connection child memento + IMemento connectionMemento = memento.createChild("connection"); //$NON-NLS-1$ + Assert.isNotNull(connectionMemento); + // Store the common attributes + connectionMemento.putString(ITerminalsConnectorConstants.PROP_DELEGATE_ID, delegateId); + + String terminalConnectorId = (String)properties.get(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID); + if (terminalConnectorId != null) { + connectionMemento.putString(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, terminalConnectorId); + } + + if (properties.get(ITerminalsConnectorConstants.PROP_FORCE_NEW) instanceof Boolean) { + connectionMemento.putBoolean(ITerminalsConnectorConstants.PROP_FORCE_NEW, ((Boolean)properties.get(ITerminalsConnectorConstants.PROP_FORCE_NEW)).booleanValue()); + } + + // Store the current encoding + ITerminalViewControl terminal = (ITerminalViewControl)item.getData(); + String encoding = terminal != null ? terminal.getEncoding() : null; + if (encoding == null || "".equals(encoding)) encoding = (String)properties.get(ITerminalsConnectorConstants.PROP_ENCODING); //$NON-NLS-1$ + if (encoding != null && !"".equals(encoding)) { //$NON-NLS-1$ + connectionMemento.putString(ITerminalsConnectorConstants.PROP_ENCODING, encoding); + } + + // Pass on to the memento handler + mementoHandler.saveState(connectionMemento, properties); + } + } + } + + /** + * Restore the view state from the given memento. + * + * @param view The terminals view. Must not be null. + * @param memento The memento. Must not be null. + */ + protected void restoreState(final TerminalsView view, IMemento memento) { + Assert.isNotNull(view); + Assert.isNotNull(memento); + + // Get the "terminalConnections" memento + memento = memento.getChild("terminalConnections"); //$NON-NLS-1$ + if (memento != null) { + // Read view id and secondary id + String id = memento.getString("id"); //$NON-NLS-1$ + String secondaryId = memento.getString("secondaryId"); //$NON-NLS-1$ + if ("null".equals(secondaryId)) secondaryId = null; //$NON-NLS-1$ + + // Get all the "connection" memento's. + IMemento[] connections = memento.getChildren("connection"); //$NON-NLS-1$ + for (IMemento connection : connections) { + // Create the properties container that holds the terminal properties + Map properties = new HashMap(); + + // Set the view id attributes + properties.put(ITerminalsConnectorConstants.PROP_ID, id); + properties.put(ITerminalsConnectorConstants.PROP_SECONDARY_ID, secondaryId); + + // Restore the common attributes + properties.put(ITerminalsConnectorConstants.PROP_DELEGATE_ID, connection.getString(ITerminalsConnectorConstants.PROP_DELEGATE_ID)); + properties.put(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID, connection.getString(ITerminalsConnectorConstants.PROP_TERMINAL_CONNECTOR_ID)); + if (connection.getBoolean(ITerminalsConnectorConstants.PROP_FORCE_NEW) != null) { + properties.put(ITerminalsConnectorConstants.PROP_FORCE_NEW, connection.getBoolean(ITerminalsConnectorConstants.PROP_FORCE_NEW)); + } + + // Restore the encoding + if (connection.getString(ITerminalsConnectorConstants.PROP_ENCODING) != null) { + properties.put(ITerminalsConnectorConstants.PROP_ENCODING, connection.getString(ITerminalsConnectorConstants.PROP_ENCODING)); + } + + // Get the terminal launcher delegate + String delegateId = (String)properties.get(ITerminalsConnectorConstants.PROP_DELEGATE_ID); + ILauncherDelegate delegate = delegateId != null ? LauncherDelegateManager.getInstance().getLauncherDelegate(delegateId, false) : null; + IMementoHandler mementoHandler = delegate != null ? (IMementoHandler)delegate.getAdapter(IMementoHandler.class) : null; + if (mementoHandler != null) { + // Pass on to the memento handler + mementoHandler.restoreState(connection, properties); + } + + // Restore the terminal connection + if (delegate != null && !properties.isEmpty()) { + delegate.execute(properties, null); + } + } + } + } + + /** + * Executes the given runnable asynchronously in the display thread. + * + * @param runnable The runnable. Must not be null. + */ + /* default */ void asyncExec(Runnable runnable) { + Assert.isNotNull(runnable); + if (PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getDisplay() != null && !PlatformUI.getWorkbench().getDisplay().isDisposed()) { + PlatformUI.getWorkbench().getDisplay().asyncExec(runnable); + } + } +} diff --git a/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/showin/GitShowInContextHandler.java b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/showin/GitShowInContextHandler.java new file mode 100644 index 00000000000..4c398b2a328 --- /dev/null +++ b/terminal/plugins/org.eclipse.tm.terminal.view.ui/src/org/eclipse/tm/terminal/view/ui/view/showin/GitShowInContextHandler.java @@ -0,0 +1,87 @@ +/******************************************************************************* + * Copyright (c) 2015, 2018 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 2.0 which accompanies this distribution, and is + * available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Wind River Systems - initial API and implementation + *******************************************************************************/ +package org.eclipse.tm.terminal.view.ui.view.showin; + +import java.io.File; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.IPath; +import org.eclipse.jface.viewers.ISelection; +import org.eclipse.jface.viewers.StructuredSelection; + +/** + * Git show in context handler implementation. + */ +@SuppressWarnings("restriction") +public class GitShowInContextHandler { + + /** + * Converts the data from the input object into a selection. + * + * @param input The input element. Must not be null. + * @return The selection or null. + */ + public static ISelection getSelection(Object input) { + Assert.isNotNull(input); + + List elements = new ArrayList(); + + if (input instanceof org.eclipse.egit.ui.internal.history.HistoryPageInput) { + org.eclipse.egit.ui.internal.history.HistoryPageInput inp = (org.eclipse.egit.ui.internal.history.HistoryPageInput) input; + + if (inp.isSingleFile()) { + elements.add(inp.getSingleFile()); + } else { + File[] fl = inp.getFileList(); + if (fl != null && fl.length > 0) { + for (File f : fl) { + if (f.canRead() && !elements.contains(f)) { + elements.add(f); + } + } + } + + IResource[] rl = inp.getItems(); + if (rl != null && rl.length > 0) { + for (IResource r : rl) { + if (r.isAccessible() && !elements.contains(r)) { + elements.add(r); + } + } + } + } + } + + return elements.isEmpty() ? null : new StructuredSelection(elements); + } + + /** + * Returns the path of the given element. + * + * @param element The element. Must not be null. + * @return The path or null. + */ + public static IPath getPath(Object element) { + Assert.isNotNull(element); + + IPath path = null; + + if (element instanceof org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode) { + path = ((org.eclipse.egit.ui.internal.repository.tree.RepositoryTreeNode)element).getPath(); + } + + return path; + } +} diff --git a/terminal/plugins/pom.xml b/terminal/plugins/pom.xml new file mode 100644 index 00000000000..64a12adce3c --- /dev/null +++ b/terminal/plugins/pom.xml @@ -0,0 +1,80 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + ../admin/pom-build.xml + + + org.eclipse.tm.terminal.plugins + + pom + + + org.eclipse.tm.terminal.control + + org.eclipse.tm.terminal.connector.local + org.eclipse.tm.terminal.connector.process + org.eclipse.tm.terminal.connector.remote + org.eclipse.tm.terminal.connector.ssh + org.eclipse.tm.terminal.connector.telnet + + org.eclipse.tm.terminal.view.core + org.eclipse.tm.terminal.view.ui + + org.eclipse.tm.terminal.test + + + + + + cdtserial + + + + true + + !nocdtserial + + + + org.eclipse.tm.terminal.connector.cdtserial + + + + + + rxtxserial + + false + + + + + rxtx + http://archive.eclipse.org/tm/updates/rxtx + p2 + + + + + diff --git a/terminal/pom.xml b/terminal/pom.xml new file mode 100644 index 00000000000..f0f3a77dc8a --- /dev/null +++ b/terminal/pom.xml @@ -0,0 +1,33 @@ + + + + + 4.0.0 + + + org.eclipse.tm.terminal + org.eclipse.tm.terminal.maven-build + 4.5.100-SNAPSHOT + admin/pom-build.xml + + + org.eclipse.tm.terminal + terminal-parent + pom + TM Terminal, Maven Master + + + plugins + features + + \ No newline at end of file