Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEugene Tarassov2011-10-05 16:59:11 -0400
committerEugene Tarassov2011-10-05 16:59:11 -0400
commit76aa890d7465462d76d89ab02ef4482a38d76a32 (patch)
tree26872f23f07446e00c6e65730da068c909fa53c9
parentf6f9934db820418b3211af08796a24359a049626 (diff)
parentb99320d65720f8887f78441d92dbc1beb3153be6 (diff)
downloadorg.eclipse.tcf-76aa890d7465462d76d89ab02ef4482a38d76a32.tar.gz
org.eclipse.tcf-76aa890d7465462d76d89ab02ef4482a38d76a32.tar.xz
org.eclipse.tcf-76aa890d7465462d76d89ab02ef4482a38d76a32.zip
Merge branch 'master' of ssh://git.eclipse.org/gitroot/tcf/org.eclipse.tcf
-rw-r--r--.gitignore2
-rw-r--r--pom.xml3
-rw-r--r--target_explorer/features/org.eclipse.tm.te.feature/feature.xml7
-rw-r--r--target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml7
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorServices.exsd8
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorUtilDelegates.exsd8
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/src/org/eclipse/tm/te/runtime/concurrent/util/ExecutorsUtil.java112
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java67
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/META-INF/MANIFEST.MF3
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/icons/obj16/synch_synch.gifbin0 -> 338 bytes
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.properties23
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.xml569
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/activator/UIPlugin.java45
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeContentProvider.java44
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeControl.java61
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeDecoratingLabelProvider.java91
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeLabelProvider.java4
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/ImageConsts.java11
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilter.java50
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilterFactory.java62
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveAllListener.java193
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveListener.java142
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/EditableSharedDocumentAdapter.java256
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalFileSaveable.java479
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalTypedElement.java306
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeEditorInput.java408
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeInput.java158
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeTypedElement.java100
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/RemoteTypedElement.java104
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/events/INodeStateListener.java26
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFChannelException.java40
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFException.java40
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFFileSystemException.java41
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CacheManager.java430
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CachePropertyTester.java37
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CommitHandler.java90
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/ContentTypeHelper.java33
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/FSTreeNodePropertyTester.java12
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/MergeHandler.java46
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/OpenFileHandler.java76
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RefreshHandler.java45
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RevertHandler.java38
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/StateManager.java259
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UpdateHandler.java89
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UserManager.java167
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.java55
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.properties55
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/PreferencesInitializer.java3
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/TargetExplorerPreferencePage.java61
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TCFUtilities.java67
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfInputStream.java170
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfOutputStream.java146
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfURLConnection.java205
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/CacheState.java22
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSModel.java102
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSTreeNode.java200
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/activator/UIPlugin.java12
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/ImageConsts.java12
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/LabelProviderDelegate.java2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/images/PeerImageDescriptor.java10
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.controls/build.properties1
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.forms/pom.xml2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.swt/pom.xml2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java4
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java4
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.classpath7
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options1
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.project28
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.settings/org.eclipse.jdt.core.prefs82
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF22
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/build.properties6
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.properties23
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml48
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/pom.xml17
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java184
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java58
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java143
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java77
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java25
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java36
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java21
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java65
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java37
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java52
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java198
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java300
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java47
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties20
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java425
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java106
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java162
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java187
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java128
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java215
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java222
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java113
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java135
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java67
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java720
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java297
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java55
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java304
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java84
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java111
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java309
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/activator/UIPlugin.java2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/interfaces/ImageConsts.java2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/actions/NewActionProvider.java6
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/editor/EditorInput.java2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/plugin.properties2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/plugin.xml10
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/activator/UIPlugin.java6
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java2
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/ImageConsts.java6
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/SWTDisplayExecutor.java (renamed from target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/EclipsePlatformDisplayExecutor.java)42
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/SWTDisplayExecutorUtilDelegate.java (renamed from target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/EclipsePlatformDisplayExecutorUtilDelegate.java)4
-rw-r--r--target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/wizards/newWizard/NewWizard.java2
118 files changed, 10591 insertions, 561 deletions
diff --git a/.gitignore b/.gitignore
index 49f591f98..1f4f04464 100644
--- a/.gitignore
+++ b/.gitignore
@@ -114,6 +114,8 @@ tests/test-dwarf/*.ncb
/target_explorer/plugins/org.eclipse.tm.te.ui.forms/bin
/target_explorer/plugins/org.eclipse.tm.te.ui.swt/target
/target_explorer/plugins/org.eclipse.tm.te.ui.swt/bin
+/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/target
+/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/bin
/target_explorer/plugins/org.eclipse.tm.te.ui.views/target
/target_explorer/plugins/org.eclipse.tm.te.ui.views/bin
/target_explorer/features/org.eclipse.tm.te.feature/target
diff --git a/pom.xml b/pom.xml
index cfcdf699f..54263ded9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -15,7 +15,7 @@
<name>TCF Parent</name>
<properties>
- <tycho-version>0.12.0</tycho-version>
+ <tycho-version>0.13.0</tycho-version>
<platform-version>3.7</platform-version>
<platform-site>http://download.eclipse.org/eclipse/updates/${platform-version}</platform-site>
<cdt-site>http://download.eclipse.org/tools/cdt/builds/hudson/cdt-nightly</cdt-site>
@@ -62,6 +62,7 @@
<module>target_explorer/plugins/org.eclipse.tm.te.ui.controls</module>
<module>target_explorer/plugins/org.eclipse.tm.te.ui.forms</module>
<module>target_explorer/plugins/org.eclipse.tm.te.ui.swt</module>
+ <module>target_explorer/plugins/org.eclipse.tm.te.ui.terminals</module>
<module>target_explorer/plugins/org.eclipse.tm.te.ui.views</module>
<module>target_explorer/plugins/org.eclipse.tm.te.tcf.core</module>
<module>target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem</module>
diff --git a/target_explorer/features/org.eclipse.tm.te.feature/feature.xml b/target_explorer/features/org.eclipse.tm.te.feature/feature.xml
index 2dc891b7a..4763ec7bf 100644
--- a/target_explorer/features/org.eclipse.tm.te.feature/feature.xml
+++ b/target_explorer/features/org.eclipse.tm.te.feature/feature.xml
@@ -97,6 +97,13 @@
unpack="false"/>
<plugin
+ id="org.eclipse.tm.te.ui.terminals"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
id="org.eclipse.tm.te.ui.views"
download-size="0"
install-size="0"
diff --git a/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml b/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml
index 79ba18bc7..272c3f5c7 100644
--- a/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml
+++ b/target_explorer/features/org.eclipse.tm.te.sdk.feature/feature.xml
@@ -92,6 +92,13 @@
unpack="false"/>
<plugin
+ id="org.eclipse.tm.te.ui.terminals.source"
+ download-size="0"
+ install-size="0"
+ version="0.0.0"
+ unpack="false"/>
+
+ <plugin
id="org.eclipse.tm.te.ui.views.source"
download-size="0"
install-size="0"
diff --git a/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties
index 338e09e2a..fb56c2f1e 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties
+++ b/target_explorer/plugins/org.eclipse.tm.te.rcp.application/src/org/eclipse/tm/te/rcp/application/nls/Messages.properties
@@ -1,5 +1,5 @@
#
-# com.windriver.vtl
+# org.eclipse.tm.te.rcp.application
# Externalized Strings.
#
diff --git a/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorServices.exsd b/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorServices.exsd
index 2a6643d53..608a3e0d3 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorServices.exsd
+++ b/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorServices.exsd
@@ -75,12 +75,12 @@
<attribute name="class" type="string">
<annotation>
<documentation>
- The class that implements &lt;code&gt;com.windriver.core.runtime.concurrent.interfaces.IWRExecutor&lt;/code&gt; or extends &lt;code&gt;com.windriver.core.runtime.concurrent.executors.AbstractDelegatingExecutorService&lt;/code&gt;.
+ The class that implements &lt;code&gt;org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutor&lt;/code&gt; or extends &lt;code&gt;org.eclipse.tm.te.runtime.concurrent.executors.AbstractDelegatingExecutorService&lt;/code&gt;.
&lt;p&gt;
The executor service implementation class must be specified either by the class attribute or the class child element!
</documentation>
<appinfo>
- <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutor"/>
+ <meta.attribute kind="java" basedOn="org.eclipse.tm.te.runtime.concurrent.executors.AbstractDelegatingExecutorService:org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutor"/>
</appinfo>
</annotation>
</attribute>
@@ -108,12 +108,12 @@ The executor service implementation class must be specified either by the class
<attribute name="class" type="string">
<annotation>
<documentation>
- The class that implements &lt;code&gt;com.windriver.core.runtime.concurrent.interfaces.IWRExecutor&lt;/code&gt; or extends &lt;code&gt;com.windriver.core.runtime.concurrent.executors.AbstractDelegatingExecutorService&lt;/code&gt;.
+ The class that implements &lt;code&gt;org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutor&lt;/code&gt; or extends &lt;code&gt;org.eclipse.tm.te.runtime.concurrent.executors.AbstractDelegatingExecutorService&lt;/code&gt;.
&lt;p&gt;
The executor service implementation class must be specified either by the class attribute or the class child element!
</documentation>
<appinfo>
- <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutor"/>
+ <meta.attribute kind="java" basedOn="org.eclipse.tm.te.runtime.concurrent.executors.AbstractDelegatingExecutorService:org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutor"/>
</appinfo>
</annotation>
</attribute>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorUtilDelegates.exsd b/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorUtilDelegates.exsd
index 4ff64843d..d69521522 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorUtilDelegates.exsd
+++ b/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/schema/executorUtilDelegates.exsd
@@ -75,12 +75,12 @@
<attribute name="class" type="string">
<annotation>
<documentation>
- The class that implements &lt;code&gt;com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate&lt;/code&gt;.
+ The class that implements &lt;code&gt;org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutorUtilDelegate&lt;/code&gt;.
&lt;p&gt;
The executor utility delegate implementation class must be specified either by the class attribute or the class child element!
</documentation>
<appinfo>
- <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate"/>
+ <meta.attribute kind="java" basedOn=":org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutorUtilDelegate"/>
</appinfo>
</annotation>
</attribute>
@@ -108,12 +108,12 @@ The executor utility delegate implementation class must be specified either by t
<attribute name="class" type="string">
<annotation>
<documentation>
- The class that implements &lt;code&gt;com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate&lt;/code&gt;.
+ The class that implements &lt;code&gt;org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutorUtilDelegate&lt;/code&gt;.
&lt;p&gt;
The executor utility delegate implementation class must be specified either by the class attribute or the class child element!
</documentation>
<appinfo>
- <meta.attribute kind="java" basedOn=":com.windriver.core.runtime.concurrent.interfaces.IWRExecutorUtilDelegate"/>
+ <meta.attribute kind="java" basedOn=":org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutorUtilDelegate"/>
</appinfo>
</annotation>
</attribute>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/src/org/eclipse/tm/te/runtime/concurrent/util/ExecutorsUtil.java b/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/src/org/eclipse/tm/te/runtime/concurrent/util/ExecutorsUtil.java
index e7a932046..13a98e687 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/src/org/eclipse/tm/te/runtime/concurrent/util/ExecutorsUtil.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.runtime.concurrent/src/org/eclipse/tm/te/runtime/concurrent/util/ExecutorsUtil.java
@@ -13,6 +13,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutorService;
+import java.util.concurrent.atomic.AtomicBoolean;
import org.eclipse.core.runtime.Assert;
import org.eclipse.tm.te.runtime.concurrent.Executors;
@@ -111,7 +112,7 @@ public final class ExecutorsUtil {
static {
EXECUTOR = (ISingleThreadedExecutor) Executors.getSharedExecutor("org.eclipse.tm.te.runtime.concurrent.executors.singleThreaded"); //$NON-NLS-1$
Assert.isNotNull(EXECUTOR);
- UI_EXECUTOR = (ISingleThreadedExecutor) Executors.getSharedExecutor("org.eclipse.tm.te.ui.executors.platform.display"); //$NON-NLS-1$
+ UI_EXECUTOR = (ISingleThreadedExecutor) Executors.getSharedExecutor("org.eclipse.tm.te.ui.executors.SWTDisplay"); //$NON-NLS-1$
}
/**
@@ -162,19 +163,68 @@ public final class ExecutorsUtil {
EXECUTOR.execute(runnable);
}
} else {
- if (EXECUTOR != null) {
- EXECUTOR.execute(runnable);
+ EXECUTOR.execute(runnable);
+ }
+ }
+ }
+
+
+ /**
+ * Schedule the given {@link Runnable} for invocation within the used
+ * executor thread and blocks the caller until the runnable got executed.
+ * <p>
+ * <b>Note:</b> The method is using {@link #wait()} to block the calling
+ * thread. Therefore the method cannot be called from within
+ * the executor thread itself.
+ *
+ * @param runnable
+ * The <code>java.lang.Runnable</code> to execute within the
+ * executor thread.
+ */
+ public static void executeWait(final Runnable runnable) {
+ Assert.isTrue(!EXECUTOR.isExecutorThread());
+ if (runnable == null) return;
+
+ // Wrap the original runnable in another runnable
+ // to notify ourself
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runnable.run();
+ } finally {
+ synchronized(runnable) {
+ runnable.notifyAll();
+ }
}
}
+ };
+
+ if (EXECUTOR instanceof ExecutorService) {
+ if (!((ExecutorService) EXECUTOR).isShutdown()
+ && !((ExecutorService) EXECUTOR).isTerminated()) {
+ EXECUTOR.execute(r);
+ }
+ } else {
+ EXECUTOR.execute(r);
+ }
+
+ synchronized(runnable) {
+ try {
+ runnable.wait();
+ } catch (InterruptedException e) {
+ /* ignored on purpose */
+ }
}
}
/**
- * Schedule the given {@link Runnable} to run the current workbench display
- * thread.
+ * Schedule the given {@link Runnable} to run the current platform display
+ * thread and blocks the caller until the runnable got executed.
*
* @param runnable
- * The runnable to execute.
+ * The <code>java.lang.Runnable</code> to execute within the
+ * UI thread.
*/
public static void executeInUI(Runnable runnable) {
if (runnable != null) {
@@ -192,6 +242,56 @@ public final class ExecutorsUtil {
}
/**
+ * Schedule the given {@link Runnable} to run the current platform display
+ * thread and blocks the caller until the runnable got executed.
+ *
+ * @param runnable
+ * The <code>java.lang.Runnable</code> to execute within the
+ * UI thread.
+ */
+ public static void executeInUIWait(final Runnable runnable) {
+ if (runnable == null) return;
+
+ final AtomicBoolean invoked = new AtomicBoolean(false);
+
+ // Wrap the original runnable in another runnable
+ // to set the invoked flag
+ Runnable r = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ runnable.run();
+ } finally {
+ invoked.set(true);
+ }
+ }
+ };
+
+ if (UI_EXECUTOR instanceof ExecutorService) {
+ if (!((ExecutorService) UI_EXECUTOR).isShutdown()
+ && !((ExecutorService) UI_EXECUTOR).isTerminated()) {
+ UI_EXECUTOR.execute(r);
+ }
+ } else {
+ if (UI_EXECUTOR != null) {
+ UI_EXECUTOR.execute(r);
+ } else {
+ invoked.set(true);
+ }
+ }
+
+ waitAndExecute(0, new IConditionTester() {
+ @Override
+ public boolean isConditionFulfilled() {
+ return invoked.get();
+ }
+ @Override
+ public void cleanup() {
+ }
+ });
+ }
+
+ /**
* Waits either for the given condition tester to signal that the condition,
* the caller want's to wait for, has been completely fulfilled or till the
* timeout runs out. If the specified condition tester is <code>null</code>,
diff --git a/target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java b/target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java
new file mode 100644
index 000000000..fc8eee27c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.runtime/src/org/eclipse/tm/te/runtime/events/DisposedEvent.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.runtime.events;
+
+import java.util.EventObject;
+
+import org.eclipse.tm.te.runtime.activator.CoreBundleActivator;
+import org.eclipse.tm.te.runtime.interfaces.tracing.ITraceIds;
+
+/**
+ * Event used to signal the disposal of an element.
+ */
+public class DisposedEvent extends EventObject {
+ private static final long serialVersionUID = -8900361742097122798L;
+
+ private final Object data;
+
+ /**
+ * Constructor.
+ *
+ * @param source The event source. Must not be <code>null</code>.
+ * <p>
+ * The event source is expected to be of type {@link CTabItem}.
+ *
+ * @param data The custom data object or <code>null</code>.
+ */
+ public DisposedEvent(Object source, Object data) {
+ super(source);
+ this.data = data;
+ }
+
+ /**
+ * Returns the custom data object associated with the disposed terminal console.
+ *
+ * @return The custom data object or <code>null</code>.
+ */
+ public final Object getData() {
+ return data;
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.EventObject#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuffer toString = new StringBuffer(getClass().getName());
+
+ String prefix = ""; //$NON-NLS-1$
+ // if debugging the event, formating them a little bit better readable.
+ if (CoreBundleActivator.getTraceHandler().isSlotEnabled(1, ITraceIds.TRACE_EVENTS))
+ prefix = "\n\t\t"; //$NON-NLS-1$
+
+ toString.append(prefix + "{source="); //$NON-NLS-1$
+ toString.append(source);
+ toString.append("}"); //$NON-NLS-1$
+
+ return toString.toString();
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/META-INF/MANIFEST.MF
index 072f96b99..70e436d92 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/META-INF/MANIFEST.MF
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/META-INF/MANIFEST.MF
@@ -18,6 +18,9 @@ Require-Bundle: org.eclipse.core.runtime;bundle-version="3.7.0",
org.eclipse.tm.te.tcf.locator;bundle-version="1.0.0",
org.eclipse.core.filesystem;bundle-version="1.3.100",
org.eclipse.ui.ide;bundle-version="3.7.0",
+ org.eclipse.compare;bundle-version="3.5.200",
+ org.eclipse.text;bundle-version="3.5.100",
+ org.eclipse.ui.workbench.texteditor;bundle-version="3.7.0",
org.eclipse.core.expressions;bundle-version="3.4.300"
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Bundle-ActivationPolicy: lazy
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/icons/obj16/synch_synch.gif b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/icons/obj16/synch_synch.gif
new file mode 100644
index 000000000..7437a027a
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/icons/obj16/synch_synch.gif
Binary files differ
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.properties b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.properties
index 7ddba5cac..aa6681902 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.properties
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.properties
@@ -28,3 +28,26 @@ FSTreeViewerFilter.systemFiles=Protected operating system files (File System (TC
PropertiesAction.label=P&roperties
PropertiesAction.tooltip=Show Properties of Selection
+
+navigatorContent.name = Target File System (TCF)
+fsmenu.open.label = Open
+fsmenu.refresh.label = Refresh
+fsmenu.update.label = Update
+fsmenu.commit.label = Commit
+fsmenu.merge.label = Merge
+fsmenu.revert.label = Revert
+temenu.open.label = Open
+temenu.refresh.label = Refresh
+temenu.update.label = Update
+temenu.commit.label = Commit
+temenu.merge.label = Merge
+temenu.revert.label = Revert
+command.refresh.name = Refresh File
+command.update.name = Update File
+command.commit.name = Commit File
+command.merge.name = Merge File
+command.revert.name = Revert File
+decorator.modified.label = Modified Cache
+decorator.outdated.label = Outdated Cache
+decorator.conflict.label = Conflicting Cache
+preference.page.name = Target Explorer \ No newline at end of file
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.xml b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.xml
index 6efc5e071..c5136680a 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.xml
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/plugin.xml
@@ -25,11 +25,16 @@
icon="icons/obj16/rootdrive.gif"
id="org.eclipse.tm.te.tcf.filesystem.navigator.content"
labelProvider="org.eclipse.tm.te.tcf.filesystem.controls.FSTreeLabelProvider"
- name="Target File System (TCF)"
+ name="%navigatorContent.name"
priority="normal">
<triggerPoints>
- <instanceof value="org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModel"/>
- <test property="org.eclipse.tm.te.tcf.locator.hasRemoteService" value="FileSystem"/>
+ <adapt
+ type="org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModel">
+ <test
+ property="org.eclipse.tm.te.tcf.locator.hasRemoteService"
+ value="FileSystem">
+ </test>
+ </adapt>
</triggerPoints>
<possibleChildren>
<instanceof value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode"/>
@@ -91,13 +96,13 @@
<menuContribution locationURI="popup:org.eclipse.tm.te.ui.controls.menu.fs?after=additions">
<separator name="group.open" visible="true"/>
<command
- commandId="org.eclipse.tm.te.tcf.filesystem.commands.open"
+ commandId="org.eclipse.ui.navigator.Open"
helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Open"
id="open"
- label="Open"
+ label="%fsmenu.open.label"
style="push">
<visibleWhen checkEnabled="false">
- <with variable="activeMenuSelection">
+ <with variable="selection">
<count value="1"/>
<iterate>
<instanceof value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode"/>
@@ -112,6 +117,166 @@
</with>
</visibleWhen>
</command>
+ <separator
+ name="group.state"
+ visible="true">
+ </separator>
+ <command
+ commandId="org.eclipse.ui.file.refresh"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Refresh"
+ icon="platform:/plugin/org.eclipse.ui/icons/full/elcl16/refresh_nav.gif"
+ id="refresh"
+ label="%fsmenu.refresh.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.update"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Update"
+ id="update"
+ label="%fsmenu.update.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.commit"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Commit"
+ id="commit"
+ label="%fsmenu.commit.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.merge"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Merge"
+ id="merge"
+ label="%fsmenu.merge.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.revert"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Revert"
+ id="revert"
+ label="%fsmenu.revert.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
<separator name="group.properties" visible="true"/>
<command
commandId="org.eclipse.ui.file.properties"
@@ -152,10 +317,10 @@
</menuContribution>
<menuContribution locationURI="popup:org.eclipse.tm.te.ui.views.TargetExplorer#Popup?after=group.open">
<command
- commandId="org.eclipse.tm.te.tcf.filesystem.commands.open"
+ commandId="org.eclipse.ui.navigator.Open"
helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Open"
id="open"
- label="Open"
+ label="%temenu.open.label"
style="push">
<visibleWhen checkEnabled="false">
<with variable="selection">
@@ -173,6 +338,166 @@
</with>
</visibleWhen>
</command>
+ <separator
+ name="group.state"
+ visible="true">
+ </separator>
+ <command
+ commandId="org.eclipse.ui.file.refresh"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Refresh"
+ icon="platform:/plugin/org.eclipse.ui/icons/full/elcl16/refresh_nav.gif"
+ id="refresh"
+ label="%temenu.refresh.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.update"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Update"
+ id="update"
+ label="%temenu.update.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.commit"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Commit"
+ id="commit"
+ label="%temenu.commit.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.merge"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Merge"
+ id="merge"
+ label="%temenu.merge.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
+ <command
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.revert"
+ helpContextId="org.eclipse.tm.te.tcf.filesystem.command_Revert"
+ id="revert"
+ label="%temenu.revert.label"
+ style="push">
+ <visibleWhen
+ checkEnabled="false">
+ <and>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
+ </iterate>
+ </with>
+ <not>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.cache.isAutoSavingOn">
+ </test>
+ </not>
+ </and>
+ </visibleWhen>
+ </command>
</menuContribution>
</extension>
@@ -194,30 +519,40 @@
class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.FSTreeNodePropertyTester"
id="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode"
namespace="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode"
- properties="isFile,isDirectory,isBinaryFile,isReadable,isWritable,isExecutable"
+ properties="isFile,isDirectory,isBinaryFile,isReadable,isWritable,isExecutable,getCacheState"
type="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
</propertyTester>
+ <propertyTester
+ class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.CachePropertyTester"
+ id="org.eclipse.tm.te.tcf.filesystem.propertytester.cache"
+ namespace="org.eclipse.tm.te.tcf.filesystem.propertytester.cache"
+ properties="isAutoSavingOn"
+ type="java.lang.Object">
+ </propertyTester>
</extension>
<!-- Target Explorer command contributions -->
<extension point="org.eclipse.ui.commands">
<command
- id="org.eclipse.tm.te.tcf.filesystem.commands.open"
- name="Open">
+ id="org.eclipse.tm.te.tcf.filesystem.commands.update"
+ name="%command.update.name">
+ </command>
+ <command
+ id="org.eclipse.tm.te.tcf.filesystem.commands.commit"
+ name="%command.commit.name">
+ </command>
+ <command
+ id="org.eclipse.tm.te.tcf.filesystem.commands.merge"
+ name="%command.merge.name">
+ </command>
+ <command
+ id="org.eclipse.tm.te.tcf.filesystem.commands.revert"
+ name="%command.revert.name">
</command>
</extension>
<!-- Target Explorer command handler contributions -->
<extension point="org.eclipse.ui.handlers">
- <handler
- class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.OpenFileHandler"
- commandId="org.eclipse.tm.te.tcf.filesystem.commands.open">
- <enabledWhen>
- <with variable="activeMenuSelection">
- <count value="1"/>
- </with>
- </enabledWhen>
- </handler>
<!-- This handler contribution is for the double click behaviour in the
Target Explore tree view -->
@@ -226,25 +561,203 @@
commandId="org.eclipse.ui.navigator.Open">
<activeWhen>
<and>
- <with variable="activePartId">
- <equals value="org.eclipse.tm.te.ui.views.TargetExplorer"/>
- </with>
- <with variable="selection">
- <count value="1"/>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
<iterate>
- <instanceof value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode"/>
- <test property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile"/>
+ <instanceof
+ value="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode">
+ </instanceof>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isFile">
+ </test>
<test
+ forcePluginActivation="true"
property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isReadable">
</test>
<not>
- <test property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isBinaryFile"/>
+ <test
+ forcePluginActivation="true"
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.isBinaryFile">
+ </test>
</not>
</iterate>
</with>
+ <with
+ variable="activePartId">
+ <or>
+ <equals
+ value="org.eclipse.tm.te.ui.views.TargetExplorer">
+ </equals>
+ <equals
+ value="org.eclipse.tm.te.ui.view.Editor">
+ </equals>
+ </or>
+ </with>
</and>
</activeWhen>
</handler>
+ <handler
+ class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.RefreshHandler"
+ commandId="org.eclipse.ui.file.refresh">
+ <activeWhen>
+ <with
+ variable="activePartId">
+ <or>
+ <equals
+ value="org.eclipse.tm.te.ui.views.TargetExplorer">
+ </equals>
+ <equals
+ value="org.eclipse.tm.te.ui.view.Editor">
+ </equals>
+ </or>
+ </with>
+ </activeWhen>
+ </handler>
+ <handler
+ class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.UpdateHandler"
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.update">
+ <enabledWhen>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.getCacheState"
+ value="outdated">
+ </test>
+ </iterate>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.CommitHandler"
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.commit">
+ <enabledWhen>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.getCacheState"
+ value="modified">
+ </test>
+ </iterate>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.MergeHandler"
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.merge">
+ <enabledWhen>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.getCacheState"
+ value="conflict">
+ </test>
+ </iterate>
+ </with>
+ </enabledWhen>
+ </handler>
+ <handler
+ class="org.eclipse.tm.te.tcf.filesystem.internal.handlers.RevertHandler"
+ commandId="org.eclipse.tm.te.tcf.filesystem.commands.revert">
+ <enabledWhen>
+ <with
+ variable="selection">
+ <count
+ value="1">
+ </count>
+ <iterate>
+ <or>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.getCacheState"
+ value="modified">
+ </test>
+ <test
+ property="org.eclipse.tm.te.tcf.filesystem.propertytester.treenode.getCacheState"
+ value="conflict">
+ </test>
+ </or>
+ </iterate>
+ </with>
+ </enabledWhen>
+ </handler>
+ </extension>
+
+ <extension point="org.eclipse.ui.decorators">
+ <decorator
+ icon="icons/ovr/ovr_modified.png"
+ id="org.eclipse.tm.te.tcf.filesystem.decorators.modified"
+ label="%decorator.modified.label"
+ lightweight="true"
+ location="TOP_RIGHT"
+ state="true">
+ <enablement>
+ <objectState
+ name="cache.state"
+ value="modified">
+ </objectState>
+ </enablement>
+ </decorator>
+ <decorator
+ icon="icons/ovr/ovr_outdated.png"
+ id="org.eclipse.tm.te.tcf.filesystem.decorators.outdated"
+ label="%decorator.outdated.label"
+ lightweight="true"
+ location="TOP_RIGHT"
+ state="true">
+ <enablement>
+ <objectState
+ name="cache.state"
+ value="outdated">
+ </objectState>
+ </enablement>
+ </decorator>
+ <decorator
+ icon="icons/ovr/ovr_conflict.png"
+ id="org.eclipse.tm.te.tcf.filesystem.decorators.conflict"
+ label="%decorator.conflict.label"
+ lightweight="true"
+ location="TOP_RIGHT"
+ state="true">
+ <enablement>
+ <objectState
+ name="cache.state"
+ value="conflict">
+ </objectState>
+ </enablement>
+ </decorator>
+ </extension>
+
+ <extension point="org.eclipse.ui.preferencePages">
+ <page
+ class="org.eclipse.tm.te.tcf.filesystem.internal.preferences.TargetExplorerPreferencePage"
+ id="org.eclipse.tm.te.tcf.filesystem.preferencePage"
+ name="%preference.page.name">
+ </page>
+ </extension>
+
+ <extension point="org.eclipse.core.runtime.adapters">
+ <factory
+ adaptableType="org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode"
+ class="org.eclipse.tm.te.tcf.filesystem.internal.adapters.NodeStateFilterFactory">
+ <adapter
+ type="org.eclipse.ui.IActionFilter">
+ </adapter>
+ </factory>
</extension>
</plugin>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/activator/UIPlugin.java
index 08b0c33bf..23fc2074c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/activator/UIPlugin.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/activator/UIPlugin.java
@@ -7,6 +7,7 @@
* Contributors:
* Wind River Systems - initial API and implementation
* William Chen (Wind River) - [345387] Open the remote files with a proper editor
+ * William Chen (Wind River) - [345552] Edit the remote files with a proper editor
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.activator;
@@ -15,11 +16,19 @@ import java.net.URL;
import java.net.URLConnection;
import java.util.Hashtable;
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.IExecutionListener;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.swt.graphics.Image;
import org.eclipse.tm.te.tcf.filesystem.internal.ImageConsts;
+import org.eclipse.tm.te.tcf.filesystem.internal.autosave.SaveAllListener;
+import org.eclipse.tm.te.tcf.filesystem.internal.autosave.SaveListener;
import org.eclipse.tm.te.tcf.filesystem.internal.url.TcfURLConnection;
+import org.eclipse.tm.te.tcf.filesystem.model.FSModel;
+import org.eclipse.ui.IWorkbenchCommandConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;
@@ -27,16 +36,19 @@ import org.osgi.service.url.AbstractURLStreamHandlerService;
import org.osgi.service.url.URLConstants;
import org.osgi.service.url.URLStreamHandlerService;
-
/**
* The activator class controls the plug-in life cycle
*/
public class UIPlugin extends AbstractUIPlugin {
- // The shared instance
+ // The shared instance of this plug-in.
private static UIPlugin plugin;
// The service registration for the "tcf" URL stream handler.
private ServiceRegistration<?> regURLStreamHandlerService;
-
+ // The listener which listens to command "SAVE" and synchronize the local file with the target.
+ private IExecutionListener saveListener;
+ // The listener which listens to command "SAVE ALL" and synchronize the local file with the target.
+ private IExecutionListener saveAllListener;
+
/**
* The constructor
*/
@@ -81,6 +93,16 @@ public class UIPlugin extends AbstractUIPlugin {
return new TcfURLConnection(u);
}
}, properties);
+ // Add the two execution listeners to command "SAVE" and "SAVE ALL".
+ ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
+ if (commandService != null) {
+ saveListener = new SaveListener();
+ Command saveCmd = commandService.getCommand(IWorkbenchCommandConstants.FILE_SAVE);
+ saveCmd.addExecutionListener(saveListener);
+ saveAllListener = new SaveAllListener();
+ Command saveAllCmd = commandService.getCommand(IWorkbenchCommandConstants.FILE_SAVE_ALL);
+ saveAllCmd.addExecutionListener(saveAllListener);
+ }
}
/* (non-Javadoc)
@@ -92,6 +114,15 @@ public class UIPlugin extends AbstractUIPlugin {
regURLStreamHandlerService.unregister();
regURLStreamHandlerService = null;
}
+ // Remove the two execution listeners.
+ ICommandService commandService = (ICommandService) PlatformUI.getWorkbench().getService(ICommandService.class);
+ if (commandService != null) {
+ Command saveCmd = commandService.getCommand(IWorkbenchCommandConstants.FILE_SAVE);
+ saveCmd.removeExecutionListener(saveListener);
+ Command saveAllCmd = commandService.getCommand(IWorkbenchCommandConstants.FILE_SAVE_ALL);
+ saveAllCmd.removeExecutionListener(saveAllListener);
+ }
+ FSModel.getInstance().dispose();
plugin = null;
super.stop(context);
}
@@ -102,12 +133,14 @@ public class UIPlugin extends AbstractUIPlugin {
@Override
protected void initializeImageRegistry(ImageRegistry registry) {
URL url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OBJ + "folder.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_FOLDER, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.FOLDER, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OBJ + "rootdrive.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_ROOT_DRIVE, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.ROOT_DRIVE, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OBJ + "rootdriveopen.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_ROOT_DRIVE_OPEN, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.ROOT_DRIVE_OPEN, ImageDescriptor.createFromURL(url));
+ url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OBJ + "synch_synch.gif"); //$NON-NLS-1$
+ registry.put(ImageConsts.COMPARE_EDITOR, ImageDescriptor.createFromURL(url));
}
/**
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeContentProvider.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeContentProvider.java
index d35287e12..2184b2ada 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeContentProvider.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeContentProvider.java
@@ -15,8 +15,9 @@ import java.util.List;
import org.eclipse.core.runtime.Assert;
import org.eclipse.jface.viewers.ITreeContentProvider;
-import org.eclipse.jface.viewers.StructuredViewer;
+import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.swt.widgets.Display;
import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IPeer;
import org.eclipse.tm.tcf.protocol.IToken;
@@ -27,6 +28,7 @@ import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle;
import org.eclipse.tm.te.tcf.core.Tcf;
import org.eclipse.tm.te.tcf.core.interfaces.IChannelManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.events.INodeStateListener;
import org.eclipse.tm.te.tcf.filesystem.model.FSModel;
import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
import org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModel;
@@ -38,7 +40,7 @@ import org.eclipse.ui.PlatformUI;
/**
* Target Explorer: File system tree content provider implementation.
*/
-public class FSTreeContentProvider implements ITreeContentProvider {
+public class FSTreeContentProvider implements ITreeContentProvider, INodeStateListener {
/**
* Static reference to the return value representing no elements.
*/
@@ -46,19 +48,22 @@ public class FSTreeContentProvider implements ITreeContentProvider {
/**
* The file system model instance associated with this file system
- * tree content provider instance. Each content provider has it's own
- * file system mode instance.
+ * tree content provider instance.
*/
- /* default*/ final FSModel model = new FSModel();
+ /* package */ final static FSModel model = FSModel.getInstance();
- /* default */ Viewer viewer = null;
+ /* package */ TreeViewer viewer = null;
+
+ public FSTreeContentProvider(){
+ model.addNodeStateListener(this);
+ }
/* (non-Javadoc)
* @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object)
*/
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
- this.viewer = viewer;
+ this.viewer = (TreeViewer) viewer;
}
/* (non-Javadoc)
@@ -66,7 +71,7 @@ public class FSTreeContentProvider implements ITreeContentProvider {
*/
@Override
public void dispose() {
- model.dispose();
+ model.removeNodeStateListener(this);
}
/**
@@ -205,6 +210,7 @@ public class FSTreeContentProvider implements ITreeContentProvider {
node.parent = rootNode;
node.peerNode = rootNode.peerNode;
rootNode.getChildren().add(node);
+ model.addNode(node);
}
}
@@ -391,6 +397,7 @@ public class FSTreeContentProvider implements ITreeContentProvider {
node.parent = parentNode;
node.peerNode = parentNode.peerNode;
parentNode.getChildren().add(node);
+ model.addNode(node);
}
}
}
@@ -417,7 +424,7 @@ public class FSTreeContentProvider implements ITreeContentProvider {
PlatformUI.getWorkbench().getDisplay().asyncExec(new Runnable() {
@Override
public void run() {
- if (viewer instanceof StructuredViewer) ((StructuredViewer)viewer).refresh(parentNode);
+ viewer.refresh(parentNode);
}
});
}
@@ -546,4 +553,23 @@ public class FSTreeContentProvider implements ITreeContentProvider {
return hasChildren;
}
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.events.INodeStateListener#stateChanged(org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode)
+ */
+ @Override
+ public void stateChanged(final FSTreeNode node) {
+ // Make sure that this node is inside of this viewer.
+ Display display = PlatformUI.getWorkbench().getDisplay();
+ if (display.getThread() == Thread.currentThread()) {
+ viewer.refresh(node);
+ } else {
+ display.asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ viewer.refresh(node);
+ }
+ });
+ }
+ }
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeControl.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeControl.java
index 7385574da..3722356f9 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeControl.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeControl.java
@@ -10,7 +10,16 @@
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.controls;
+import java.util.Collections;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.expressions.EvaluationContext;
+import org.eclipse.jface.viewers.DoubleClickEvent;
+import org.eclipse.jface.viewers.IDoubleClickListener;
+import org.eclipse.jface.viewers.ILabelDecorator;
import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
@@ -23,15 +32,21 @@ import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
import org.eclipse.tm.te.ui.interfaces.IUIConstants;
import org.eclipse.tm.te.ui.trees.AbstractTreeControl;
+import org.eclipse.ui.IDecoratorManager;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartSite;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+import org.eclipse.ui.navigator.ICommonActionConstants;
import org.eclipse.ui.part.MultiPageSelectionProvider;
/**
* Target Explorer: File system browser control.
*/
-public class FSTreeControl extends AbstractTreeControl implements ISelectionChangedListener{
+public class FSTreeControl extends AbstractTreeControl implements ISelectionChangedListener, IDoubleClickListener {
/**
* Constructor.
@@ -71,6 +86,7 @@ public class FSTreeControl extends AbstractTreeControl implements ISelectionChan
column.setWidth(200);
}
tree.setHeaderVisible(hasColumns());
+ viewer.addDoubleClickListener(this);
}
/**
@@ -95,7 +111,11 @@ public class FSTreeControl extends AbstractTreeControl implements ISelectionChan
*/
@Override
protected ILabelProvider doCreateTreeViewerLabelProvider(TreeViewer viewer) {
- return new FSTreeLabelProvider(viewer);
+ FSTreeLabelProvider labelProvider = new FSTreeLabelProvider(viewer);
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IDecoratorManager manager = workbench.getDecoratorManager();
+ ILabelDecorator decorator = manager.getLabelDecorator();
+ return new FSTreeDecoratingLabelProvider(labelProvider,decorator);
}
/* (non-Javadoc)
@@ -130,8 +150,7 @@ public class FSTreeControl extends AbstractTreeControl implements ISelectionChan
return IUIConstants.ID_CONTROL_MENUS_BASE + ".menu.fs"; //$NON-NLS-1$;
}
- /*
- * (non-Javadoc)
+ /* (non-Javadoc)
* @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
*/
@Override
@@ -149,4 +168,38 @@ public class FSTreeControl extends AbstractTreeControl implements ISelectionChan
}
}
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
+ */
+ @Override
+ public void doubleClick(DoubleClickEvent event) {
+ // If an handled and enabled command is registered for the ICommonActionConstants.OPEN
+ // retargetable action id, redirect the double click handling to the command handler.
+ //
+ // Note: The default tree node expansion must be re-implemented in the active handler!
+ ICommandService service = (ICommandService)PlatformUI.getWorkbench().getService(ICommandService.class);
+ Command command = service != null ? service.getCommand(ICommonActionConstants.OPEN) : null;
+ if (command != null && command.isDefined() && command.isEnabled()) {
+ try {
+ ISelection selection = event.getSelection();
+ EvaluationContext ctx = new EvaluationContext(null, selection);
+ ctx.addVariable(ISources.ACTIVE_CURRENT_SELECTION_NAME, selection);
+ ctx.addVariable(ISources.ACTIVE_MENU_SELECTION_NAME, selection);
+ ctx.addVariable(ISources.ACTIVE_WORKBENCH_WINDOW_NAME, PlatformUI.getWorkbench().getActiveWorkbenchWindow());
+ IWorkbenchPart part = getParentPart();
+ if (part != null) {
+ IWorkbenchPartSite site = part.getSite();
+ ctx.addVariable(ISources.ACTIVE_PART_ID_NAME, site.getId());
+ ctx.addVariable(ISources.ACTIVE_PART_NAME, part);
+ ctx.addVariable(ISources.ACTIVE_SITE_NAME, site);
+ ctx.addVariable(ISources.ACTIVE_SHELL_NAME, site.getShell());
+ }
+ ExecutionEvent executionEvent = new ExecutionEvent(command, Collections.EMPTY_MAP, part, ctx);
+ command.executeWithChecks(executionEvent);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeDecoratingLabelProvider.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeDecoratingLabelProvider.java
new file mode 100644
index 000000000..0b07e5f02
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeDecoratingLabelProvider.java
@@ -0,0 +1,91 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.controls;
+
+import org.eclipse.jface.viewers.DecoratingLabelProvider;
+import org.eclipse.jface.viewers.ILabelDecorator;
+import org.eclipse.jface.viewers.ITableLabelProvider;
+import org.eclipse.jface.viewers.LabelDecorator;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * A subclass of DecoratingLabelProvider provides an FS Tree Viewer
+ * with a label provider which combines a nested label provider and an optional
+ * decorator. The decorator decorates the label text, image
+ * provided by the nested label provider.
+ *
+ */
+public class FSTreeDecoratingLabelProvider extends DecoratingLabelProvider implements ITableLabelProvider {
+
+ //The label provider for the execution context viewer.
+ private FSTreeLabelProvider fProvider;
+ //The label decorator decorating the above label provider.
+ private ILabelDecorator fDecorator;
+
+ /**
+ * Create a FSTreeDecoratingLabelProvider with an FSTreeLabelProvider and a decorator.
+ *
+ * @param provider The label provider to be decorated.
+ * @param decorator The label decorator.
+ */
+ public FSTreeDecoratingLabelProvider(FSTreeLabelProvider provider, ILabelDecorator decorator) {
+ super(provider, decorator);
+ fProvider = provider;
+ fDecorator = decorator;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int)
+ */
+ @Override
+ public Image getColumnImage(Object element, int columnIndex) {
+ Image image = fProvider.getColumnImage(element, columnIndex);
+ if (columnIndex == 0 && fDecorator != null) {
+ if (fDecorator instanceof LabelDecorator) {
+ LabelDecorator ld2 = (LabelDecorator) fDecorator;
+ Image decorated = ld2.decorateImage(image, element, getDecorationContext());
+ if (decorated != null) {
+ return decorated;
+ }
+ } else {
+ Image decorated = fDecorator.decorateImage(image, element);
+ if (decorated != null) {
+ return decorated;
+ }
+ }
+ }
+ return image;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int)
+ */
+ @Override
+ public String getColumnText(Object element, int columnIndex) {
+ String text = fProvider.getColumnText(element, columnIndex);
+ if (columnIndex == 0 && fDecorator != null) {
+ if (fDecorator instanceof LabelDecorator) {
+ LabelDecorator ld2 = (LabelDecorator) fDecorator;
+ String decorated = ld2.decorateText(text, element, getDecorationContext());
+ if (decorated != null) {
+ return decorated;
+ }
+ } else {
+ String decorated = fDecorator.decorateText(text, element);
+ if (decorated != null) {
+ return decorated;
+ }
+ }
+ }
+ return text;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeLabelProvider.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeLabelProvider.java
index 1b843dc4c..36e3df63c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeLabelProvider.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/controls/FSTreeLabelProvider.java
@@ -101,9 +101,9 @@ public class FSTreeLabelProvider extends LabelProvider implements ITableLabelPro
if (element instanceof FSTreeNode) {
FSTreeNode node = (FSTreeNode)element;
if ("FSRootDirNode".equals(node.type)) {//$NON-NLS-1$
- return isExpanded ? UIPlugin.getImage(ImageConsts.IMAGE_ROOT_DRIVE_OPEN) : UIPlugin.getImage(ImageConsts.IMAGE_ROOT_DRIVE);
+ return isExpanded ? UIPlugin.getImage(ImageConsts.ROOT_DRIVE_OPEN) : UIPlugin.getImage(ImageConsts.ROOT_DRIVE);
} else if ("FSDirNode".equals(node.type)) { //$NON-NLS-1$
- return isExpanded ? PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER) : UIPlugin.getImage(ImageConsts.IMAGE_FOLDER);
+ return isExpanded ? PlatformUI.getWorkbench().getSharedImages().getImage(ISharedImages.IMG_OBJ_FOLDER) : UIPlugin.getImage(ImageConsts.FOLDER);
} else if ("FSFileNode".equals(node.type)) { //$NON-NLS-1$
String key = node.name;
Image image = UIPlugin.getImage(key);
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/ImageConsts.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/ImageConsts.java
index a5b6fb7e2..73a20ba45 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/ImageConsts.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/ImageConsts.java
@@ -33,15 +33,20 @@ public interface ImageConsts {
/**
* The key to access the base folder object image.
*/
- public static final String IMAGE_FOLDER = "Folder"; //$NON-NLS-1$
+ public static final String FOLDER = "Folder"; //$NON-NLS-1$
/**
* The key to access the base folder object image.
*/
- public static final String IMAGE_ROOT_DRIVE = "RootDrive"; //$NON-NLS-1$
+ public static final String ROOT_DRIVE = "RootDrive"; //$NON-NLS-1$
/**
* The key to access the base folder object image.
*/
- public static final String IMAGE_ROOT_DRIVE_OPEN = "RootDriveOpen"; //$NON-NLS-1$
+ public static final String ROOT_DRIVE_OPEN = "RootDriveOpen"; //$NON-NLS-1$
+
+ /**
+ * The key to access the image of compare editor.
+ */
+ public static final String COMPARE_EDITOR = "CompareEditor"; //$NON-NLS-1$
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilter.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilter.java
new file mode 100644
index 000000000..f2fdb240b
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilter.java
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.adapters;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.StateManager;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IActionFilter;
+
+/**
+ * This action filter wraps an FSTreeNode and test its attribute of "cache.state".
+ * It serves as the expression filter of decorations of Target Explorer.
+ */
+public class NodeStateFilter implements IActionFilter {
+ private FSTreeNode node;
+
+ /**
+ * Constructor.
+ *
+ * @param node
+ * The wrapped tree node. Must not be <code>null</code>.
+ */
+ public NodeStateFilter(FSTreeNode node) {
+ Assert.isNotNull(node);
+ this.node = node;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionFilter#testAttribute(java.lang.Object, java.lang.String, java.lang.String)
+ */
+ @Override
+ public boolean testAttribute(Object target, String name, String value) {
+ if (name.equals("cache.state") && node.isFile()) { //$NON-NLS-1$
+ CacheState state = StateManager.getInstance().getCacheState(node);
+ if (value == null)
+ value = CacheState.consistent.name();
+ return value.equals(state.name());
+ }
+ return false;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilterFactory.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilterFactory.java
new file mode 100644
index 000000000..0e3ca1d74
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/adapters/NodeStateFilterFactory.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.adapters;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.eclipse.core.runtime.IAdapterFactory;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IActionFilter;
+
+/**
+ * The adapter factory of <code>FSTreeNode</code> over <code>IActionFilter</code>
+ */
+@SuppressWarnings("rawtypes")
+public class NodeStateFilterFactory implements IAdapterFactory {
+ // The ADAPTERS adapted by this factory.
+ private static Class[] ADAPTERS = {IActionFilter.class};
+ // The fFilters map caching fFilters for FS nodes.
+ private Map<FSTreeNode, NodeStateFilter> filters;
+
+ /**
+ * Constructor.
+ */
+ public NodeStateFilterFactory(){
+ this.filters = Collections.synchronizedMap(new HashMap<FSTreeNode, NodeStateFilter>());
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdapterFactory#getAdapter(java.lang.Object, java.lang.Class)
+ */
+ @Override
+ public Object getAdapter(Object adaptableObject, Class adapterType) {
+ if(adaptableObject instanceof FSTreeNode){
+ FSTreeNode node = (FSTreeNode) adaptableObject;
+ NodeStateFilter filter = filters.get(node);
+ if(filter == null){
+ filter = new NodeStateFilter(node);
+ filters.put(node, filter);
+ }
+ return filter;
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdapterFactory#getAdapterList()
+ */
+ @Override
+ public Class[] getAdapterList() {
+ return ADAPTERS;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveAllListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveAllListener.java
new file mode 100644
index 000000000..5c44dc833
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveAllListener.java
@@ -0,0 +1,193 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * William Chen (Wind River) - [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.autosave;
+
+import java.io.File;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.compare.CompareUI;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.LocalTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.MergeEditorInput;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.RemoteTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.CacheManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.StateManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
+import org.eclipse.tm.te.tcf.filesystem.model.FSModel;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The execution listener of command "SAVE ALL", which synchronizes the local
+ * file with the one on the target server after it is saved.
+ */
+public class SaveAllListener implements IExecutionListener {
+ // Dirty nodes that should be saved and synchronized.
+ private List<FSTreeNode> fDirtyNodes;
+ // The file system fModel storing the existing FSTreeNodes.
+ private FSModel fModel;
+ /**
+ * Create the listener listening to command "SAVE ALL".
+ */
+ public SaveAllListener() {
+ this.fModel = FSModel.getInstance();
+ this.fDirtyNodes = new ArrayList<FSTreeNode>();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#postExecuteSuccess(java.lang.String, java.lang.Object)
+ */
+ @Override
+ public void postExecuteSuccess(String commandId, Object returnValue) {
+ if (!fDirtyNodes.isEmpty()) {
+ try {
+ List<FSTreeNode> modified = new ArrayList<FSTreeNode>();
+ List<FSTreeNode> conflicts = new ArrayList<FSTreeNode>();
+ for (FSTreeNode node : fDirtyNodes) {
+ // Refresh the dirty nodes and get their latest states.
+ StateManager.getInstance().refreshState(node);
+ CacheState state = StateManager.getInstance().getCacheState(node);
+ switch (state) {
+ case consistent:
+ break;
+ case outdated:
+ break;
+ case modified:
+ // Reclassifying
+ modified.add(node);
+ break;
+ case conflict:
+ // Reclassifying
+ conflicts.add(node);
+ break;
+ }
+ }
+
+ if (CacheManager.getInstance().isAutoSaving()) {
+ // If auto saving is on.
+ if (!modified.isEmpty()) {
+ // Upload the modified nodes.
+ CacheManager.getInstance().upload(modified.toArray(new FSTreeNode[modified.size()]));
+ }
+ if (!conflicts.isEmpty()) {
+ // Merge the conflicting ones.
+ mergeConflicts(conflicts);
+ }
+ }
+ } catch (TCFException tcfe) {
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MessageDialog.openError(parent, Messages.StateManager_RefreshFailureTitle, tcfe.getLocalizedMessage());
+ }
+ }
+ }
+
+ /**
+ * Merge those conflicting nodes.
+ *
+ * @param conflicts The conflicting nodes.
+ */
+ private void mergeConflicts(List<FSTreeNode> conflicts) {
+ for (FSTreeNode node : conflicts) {
+ String title = Messages.SaveAllListener_StateChangedDialogTitle;
+ String message = NLS.bind(Messages.SaveAllListener_SingularMessage, node.name);
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ IWorkbenchPage page = window.getActivePage();
+ Shell parent = window.getShell();
+ MessageDialog msgDialog = new MessageDialog(parent, title, null, message,
+ MessageDialog.QUESTION, new String[] { Messages.SaveAllListener_Merge,
+ Messages.SaveAllListener_SaveAnyway, Messages.SaveAllListener_Cancel }, 0);
+ int index = msgDialog.open();
+ if (index == 0) { // Merge
+ LocalTypedElement local = new LocalTypedElement(node);
+ RemoteTypedElement remote = new RemoteTypedElement(node);
+ MergeEditorInput mergeInput = new MergeEditorInput(local, remote, page);
+ CompareUI.openCompareDialog(mergeInput);
+ } else if (index == 1) { // Save anyway
+ CacheManager.getInstance().upload(conflicts.toArray(new FSTreeNode[conflicts.size()]));
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#preExecute(java.lang.String, org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public void preExecute(String commandId, ExecutionEvent event) {
+ fDirtyNodes.clear();
+ IWorkbenchPage page = HandlerUtil.getActiveWorkbenchWindow(event).getActivePage();
+ IEditorPart[] editors = page.getDirtyEditors();
+ for (IEditorPart editor : editors) {
+ IEditorInput input = editor.getEditorInput();
+ FSTreeNode node = getEditedNode(input);
+ if (node != null) {
+ // If it is a modified node, add it to the dirty node list.
+ fDirtyNodes.add(node);
+ }
+ }
+ }
+
+ /**
+ * Get the corresponding FSTreeNode from the input.
+ * If the input has no corresponding FSTreeNode, return null;
+ * @param input The editor input.
+ * @return The corresponding FSTreeNode or null if it has not.
+ */
+ private FSTreeNode getEditedNode(IEditorInput input){
+ if (input instanceof IURIEditorInput) {
+ //Get the file that is being edited.
+ IURIEditorInput fileInput = (IURIEditorInput) input;
+ URI uri = fileInput.getURI();
+ try {
+ IFileStore store = EFS.getStore(uri);
+ File localFile = store.toLocalFile(0, new NullProgressMonitor());
+ if (localFile != null) {
+ // Get the file's mapped FSTreeNode.
+ FSTreeNode node = fModel.getTreeNode(localFile.toString());
+ return node;
+ }
+ }catch(CoreException e){}
+ }
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#notHandled(java.lang.String, org.eclipse.core.commands.NotHandledException)
+ */
+ @Override
+ public void notHandled(String commandId, NotHandledException exception) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#postExecuteFailure(java.lang.String, org.eclipse.core.commands.ExecutionException)
+ */
+ @Override
+ public void postExecuteFailure(String commandId, ExecutionException exception) {
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveListener.java
new file mode 100644
index 000000000..a4ffef507
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/autosave/SaveListener.java
@@ -0,0 +1,142 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * William Chen (Wind River) - [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.autosave;
+
+import java.io.File;
+import java.net.URI;
+
+import org.eclipse.compare.CompareUI;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.core.commands.IExecutionListener;
+import org.eclipse.core.commands.NotHandledException;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.LocalTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.MergeEditorInput;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.RemoteTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.CacheManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.StateManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
+import org.eclipse.tm.te.tcf.filesystem.model.FSModel;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IURIEditorInput;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The execution listener of command "SAVE", which synchronizes the local file
+ * with the one on the target server after it is saved.
+ */
+public class SaveListener implements IExecutionListener {
+ // Dirty node that should be committed or merged.
+ private FSTreeNode dirtyNode;
+ // The file system fModel.
+ private FSModel model;
+
+ /**
+ * Create a SaveListener listening to command "SAVE".
+ */
+ public SaveListener() {
+ this.model = FSModel.getInstance();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#postExecuteSuccess(java.lang.String, java.lang.Object)
+ */
+ @Override
+ public void postExecuteSuccess(String commandId, Object returnValue) {
+ if (dirtyNode != null) {
+ try{
+ // Refresh the fDirtyNode's state.
+ StateManager.getInstance().refreshState(dirtyNode);
+ if (CacheManager.getInstance().isAutoSaving()) {
+ CacheState state = StateManager.getInstance().getCacheState(dirtyNode);
+ switch (state) {
+ case conflict:
+ String title = Messages.SaveListener_StateChangedDialogTitle;
+ String message = NLS.bind(Messages.SaveListener_StateChangedMessage, dirtyNode.name);
+ IWorkbenchWindow window = PlatformUI.getWorkbench().getActiveWorkbenchWindow();
+ IWorkbenchPage page = window.getActivePage();
+ Shell parent = window.getShell();
+ MessageDialog msgDialog = new MessageDialog(parent, title, null, message, MessageDialog.QUESTION,
+ new String[] { Messages.SaveListener_Merge, Messages.SaveListener_SaveAnyway, Messages.SaveListener_Cancel }, 0);
+ int index = msgDialog.open();
+ if (index == 0) {// Merge
+ LocalTypedElement local = new LocalTypedElement(dirtyNode);
+ RemoteTypedElement remote = new RemoteTypedElement(dirtyNode);
+ MergeEditorInput mergeInput = new MergeEditorInput(local, remote, page);
+ CompareUI.openCompareDialog(mergeInput);
+ } else if (index == 1) {// Save anyway.
+ CacheManager.getInstance().upload(dirtyNode);
+ }
+ break;
+ case modified:
+ // Save anyway
+ CacheManager.getInstance().upload(dirtyNode);
+ break;
+ case consistent:
+ break;
+ case outdated:
+ break;
+ }
+ }
+ }catch(TCFException tcfe){
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MessageDialog.openError(parent, Messages.StateManager_RefreshFailureTitle, tcfe.getLocalizedMessage());
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#preExecute(java.lang.String, org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public void preExecute(String commandId, ExecutionEvent event) {
+ dirtyNode = null;
+ IEditorInput input = HandlerUtil.getActiveEditorInput(event);
+ if (input instanceof IURIEditorInput) {
+ IURIEditorInput fileInput = (IURIEditorInput) input;
+ URI uri = fileInput.getURI();
+ try {
+ IFileStore store = EFS.getStore(uri);
+ File localFile = store.toLocalFile(0, new NullProgressMonitor());
+ if (localFile != null) {
+ dirtyNode = model.getTreeNode(localFile.toString());
+ }
+ }catch(CoreException e){
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#notHandled(java.lang.String, org.eclipse.core.commands.NotHandledException)
+ */
+ @Override
+ public void notHandled(String commandId, NotHandledException exception) {
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.IExecutionListener#postExecuteFailure(java.lang.String, org.eclipse.core.commands.ExecutionException)
+ */
+ @Override
+ public void postExecuteFailure(String commandId, ExecutionException exception) {
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/EditableSharedDocumentAdapter.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/EditableSharedDocumentAdapter.java
new file mode 100644
index 000000000..310302dfb
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/EditableSharedDocumentAdapter.java
@@ -0,0 +1,256 @@
+/*******************************************************************************
+ * Copyright (c) 2005, 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import org.eclipse.compare.SharedDocumentAdapter;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+import org.eclipse.ui.texteditor.IElementStateListener;
+
+/**
+ * A shared document adapter that tracks whether the element is connected to a
+ * shared document and whether the contents have been flushed from a compare
+ * viewer. When contents are flushed, this adapter will connect to the document
+ * provider to ensure that the changes are not lost (see
+ * {@link #hasBufferedContents()}). In order to avoid a leak, the buffer must
+ * either be saved (see
+ * {@link #saveDocument(IEditorInput, boolean, IProgressMonitor)}) or released
+ * (see {@link #releaseBuffer()}).
+ * <p>
+ * This adapter must have a one-to-one correspondence to a typed element.
+ *
+ * @since 3.7 - Copied from
+ * org.eclipse.team.internal.ui.synchronize.EditableSharedDocumentAdapter
+ */
+public class EditableSharedDocumentAdapter extends SharedDocumentAdapter implements IElementStateListener {
+
+ private int connectionCount;
+ private final ISharedDocumentAdapterListener listener;
+ private IEditorInput bufferedKey;
+
+ /**
+ * Interface that provides this adapter with the state of the typed element
+ * and supports call backs to the element when the adapter state changes.
+ */
+ public interface ISharedDocumentAdapterListener {
+
+ /**
+ * Method that is invoked when the adapter connects to the document
+ * provider. This method is only invoked when the adapter first connects
+ * to the document.
+ */
+ void handleDocumentConnected();
+
+ /**
+ * Method that is invoked when the adapter disconnects from the document
+ * provider. This method is only invoked when the adapter no longer has
+ * any connection to the document provider.
+ */
+ void handleDocumentDisconnected();
+
+ /**
+ * Method invoked when changes in the document are flushed to the
+ * adapter.
+ */
+ void handleDocumentFlushed();
+
+ /**
+ * Method invoked when the file behind the shared document is deleted.
+ */
+ void handleDocumentDeleted();
+
+ /**
+ * Method invoked when the document dirty state changes from dirty to
+ * clean.
+ */
+ void handleDocumentSaved();
+ }
+
+ /**
+ * Create the shared document adapter for the given element.
+ *
+ * @param listener
+ * access to element internals
+ */
+ public EditableSharedDocumentAdapter(ISharedDocumentAdapterListener listener) {
+ super();
+ this.listener = listener;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.SharedDocumentAdapter#connect(org.eclipse.ui.texteditor.IDocumentProvider, org.eclipse.ui.IEditorInput)
+ */
+ @Override
+ public void connect(IDocumentProvider provider, IEditorInput documentKey)
+ throws CoreException {
+ super.connect(provider, documentKey);
+ connectionCount++;
+ if (connectionCount == 1) {
+ provider.addElementStateListener(this);
+ listener.handleDocumentConnected();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.SharedDocumentAdapter#disconnect(org.eclipse.ui.texteditor.IDocumentProvider, org.eclipse.ui.IEditorInput)
+ */
+ @Override
+ public void disconnect(IDocumentProvider provider, IEditorInput documentKey) {
+ try {
+ super.disconnect(provider, documentKey);
+ } finally {
+ if (connectionCount > 0)
+ connectionCount--;
+ if (connectionCount == 0) {
+ provider.removeElementStateListener(this);
+ listener.handleDocumentDisconnected();
+ }
+ }
+ }
+
+ /**
+ * Return whether the element is connected to a shared document.
+ *
+ * @return whether the element is connected to a shared document
+ */
+ public boolean isConnected() {
+ return connectionCount > 0;
+ }
+
+ /**
+ * Save the shared document of the element of this adapter.
+ *
+ * @param input
+ * the document key of the element.
+ * @param monitor
+ * a progress monitor
+ * @return whether the save succeeded or not
+ * @throws CoreException
+ */
+ public boolean saveDocument(IEditorInput input, IProgressMonitor monitor)
+ throws CoreException {
+ if (isConnected()) {
+ IDocumentProvider provider = SharedDocumentAdapter
+ .getDocumentProvider(input);
+ try {
+ saveDocument(provider, input, provider.getDocument(input),
+ true, monitor);
+ } finally {
+ // When we write the document, remove out hold on the buffer
+ releaseBuffer();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Release the buffer if this adapter has buffered the contents in response
+ * to a
+ * {@link #flushDocument(IDocumentProvider, IEditorInput, IDocument, boolean)}
+ * .
+ */
+ public void releaseBuffer() {
+ if (bufferedKey != null) {
+ IDocumentProvider provider = SharedDocumentAdapter
+ .getDocumentProvider(bufferedKey);
+ provider.disconnect(bufferedKey);
+ bufferedKey = null;
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.ISharedDocumentAdapter#flushDocument(org.eclipse.ui.texteditor.IDocumentProvider, org.eclipse.ui.IEditorInput, org.eclipse.jface.text.IDocument, boolean)
+ */
+ @Override
+ public void flushDocument(IDocumentProvider provider,
+ IEditorInput documentKey, IDocument document, boolean overwrite)
+ throws CoreException {
+ if (!hasBufferedContents()) {
+ // On a flush, make an extra connection to the shared document so it
+ // will be kept even
+ // if it is no longer being viewed.
+ bufferedKey = documentKey;
+ provider.connect(bufferedKey);
+ }
+ this.listener.handleDocumentFlushed();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IElementStateListener#elementContentAboutToBeReplaced(java.lang.Object)
+ */
+ @Override
+ public void elementContentAboutToBeReplaced(Object element) {
+ // Nothing to do
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IElementStateListener#elementContentReplaced(java.lang.Object)
+ */
+ @Override
+ public void elementContentReplaced(Object element) {
+ // Nothing to do
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IElementStateListener#elementDeleted(java.lang.Object)
+ */
+ @Override
+ public void elementDeleted(Object element) {
+ listener.handleDocumentDeleted();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IElementStateListener#elementDirtyStateChanged(java.lang.Object, boolean)
+ */
+ @Override
+ public void elementDirtyStateChanged(Object element, boolean isDirty) {
+ if (!isDirty) {
+ this.listener.handleDocumentSaved();
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.texteditor.IElementStateListener#elementMoved(java.lang.Object, java.lang.Object)
+ */
+ @Override
+ public void elementMoved(Object originalElement, Object movedElement) {
+ // Nothing to do
+ }
+
+ /**
+ * Return whether the adapter has buffered contents. The adapter buffers
+ * contents by connecting to the document through the document provider.
+ * This means that the adapter must be disconnected either by saving or
+ * discarding the buffer.
+ *
+ * @return whether the adapter has buffered contents
+ */
+ public boolean hasBufferedContents() {
+ return bufferedKey != null;
+ }
+
+ /**
+ * Override getDocumentKey in the super class to provide an editor input
+ * when the element is a <code>LocalTypedElement</code>.
+ */
+ @Override
+ public IEditorInput getDocumentKey(Object element) {
+ if (element instanceof LocalTypedElement) {
+ LocalTypedElement localElement = (LocalTypedElement) element;
+ return localElement.getEditorInput();
+ }
+ return super.getDocumentKey(element);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalFileSaveable.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalFileSaveable.java
new file mode 100644
index 000000000..be42037ed
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalFileSaveable.java
@@ -0,0 +1,479 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.compare.ICompareContainer;
+import org.eclipse.compare.IContentChangeListener;
+import org.eclipse.compare.IContentChangeNotifier;
+import org.eclipse.compare.ISharedDocumentAdapter;
+import org.eclipse.compare.SharedDocumentAdapter;
+import org.eclipse.compare.contentmergeviewer.ContentMergeViewer;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.CacheManager;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISaveablesLifecycleListener;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.Saveable;
+import org.eclipse.ui.SaveablesLifecycleEvent;
+import org.eclipse.ui.texteditor.IDocumentProvider;
+
+/**
+ * A <code>LocalFileSaveable</code> is used as the saveable object that provides
+ * the save behavior for the merge editor input(<code>MergeEditorInput</code>).
+ */
+public class LocalFileSaveable extends Saveable implements
+ IPropertyChangeListener, ISharedDocumentAdapterListener,
+ IContentChangeListener {
+ // The property listener list.
+ private ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+
+ // The merge input that provides the left and the right compared elements.
+ private final MergeInput input;
+
+ // The input of the editor that provides the comparing view.
+ private final MergeEditorInput editorInput;
+
+ // If the current document of the file is being saved.
+ private boolean saving;
+
+ // The local file element.
+ private LocalTypedElement fileElement;
+
+ // The document provided by the local file.
+ private IDocument document;
+
+ // If the current document has been connected.
+ private boolean connected;
+
+ /**
+ * Create the file-based saveable comparison.
+ *
+ * @param input
+ * the compare input to be save
+ * @param editorInput
+ * the editor input containing the comparison
+ * @param fileElement
+ * the file element that handles the saving and change
+ * notification
+ */
+ public LocalFileSaveable(MergeInput input, MergeEditorInput editorInput, LocalTypedElement fileElement) {
+ Assert.isNotNull(input);
+
+ this.input = input;
+ this.editorInput = editorInput;
+ this.fileElement = fileElement;
+ this.fileElement.addContentChangeListener(this);
+ this.fileElement.setDocumentListener(this);
+ }
+
+ /**
+ * Dispose of the saveable.
+ */
+ public void dispose() {
+ fileElement.removeContentChangeListener(this);
+ fileElement.discardBuffer();
+ fileElement.setDocumentListener(null);
+ }
+
+ /**
+ * Performs the save.
+ *
+ * @param monitor The progress monitor.
+ *
+ * @throws CoreException If the save operation fails.
+ */
+ protected void performSave(IProgressMonitor monitor) throws CoreException {
+ try {
+ saving = true;
+ monitor.beginTask(null, 100);
+ // First, we need to flush the viewers so the changes get buffered
+ // in the input
+ flushViewers(monitor);
+ // Then we tell the input to commit its changes
+ // Only the left is ever saveable
+ if (fileElement.isDirty()) {
+ if (fileElement.isConnected()) {
+ fileElement.store2Document(monitor);
+ } else {
+ fileElement.store2Cache(monitor);
+ }
+ }
+ } finally {
+ // Make sure we fire a change for the compare input to update the
+ // viewers
+ fireInputChange();
+ setDirty(false);
+ saving = false;
+ monitor.done();
+ //Trigger upload action
+ FSTreeNode node = fileElement.getFSTreeNode();
+ CacheManager.getInstance().upload(node);
+ }
+ }
+
+ /**
+ * Flush the contents of any viewers into the compare input.
+ *
+ * @param monitor
+ * a progress monitor
+ * @throws CoreException
+ */
+ protected void flushViewers(IProgressMonitor monitor) throws CoreException {
+ editorInput.saveChanges(monitor);
+ }
+
+ /**
+ * Fire an input change for the compare input after it has been saved.
+ */
+ protected void fireInputChange() {
+ editorInput.getCompareResult().fireInputChanged();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#isDirty()
+ */
+ @Override
+ public boolean isDirty() {
+ return editorInput.isSaveNeeded();
+ }
+
+ /**
+ * Marks the editor input dirty.
+ *
+ * @param dirty <code>True</code> if the editor is dirty, <code>false</code> if not.
+ */
+ protected void setDirty(boolean dirty) {
+ if (isDirty() != dirty) {
+ editorInput.setDirty(dirty);
+ firePropertyChange(IWorkbenchPartConstants.PROP_DIRTY);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#getName()
+ */
+ @Override
+ public String getName() {
+ // Return the name of the file element as held in the compare input
+ if (fileElement.equals(input.getLeft())) {
+ return input.getLeft().getName();
+ }
+ if (fileElement.equals(input.getRight())) {
+ return input.getRight().getName();
+ }
+
+ // Fallback call returning name of the main non-null element of the input
+ //
+ // see org.eclipse.team.internal.ui.mapping.AbstractCompareInput#getMainElement()
+ return input.getName();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#getToolTipText()
+ */
+ @Override
+ public String getToolTipText() {
+ return editorInput.getToolTipText();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#getImageDescriptor()
+ */
+ @Override
+ public ImageDescriptor getImageDescriptor() {
+ Image image = input.getImage();
+ if (image != null)
+ return ImageDescriptor.createFromImage(image);
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ @Override
+ public void propertyChange(PropertyChangeEvent e) {
+ String propertyName = e.getProperty();
+ if (CompareEditorInput.DIRTY_STATE.equals(propertyName)) {
+ boolean changed = false;
+ Object newValue = e.getNewValue();
+ if (newValue instanceof Boolean)
+ changed = ((Boolean) newValue).booleanValue();
+
+ ContentMergeViewer cmv = (ContentMergeViewer) e.getSource();
+
+ if (fileElement.equals(input.getLeft())) {
+ if (changed && cmv.internalIsLeftDirty())
+ setDirty(changed);
+ else if (!changed && !cmv.internalIsLeftDirty()) {
+ setDirty(changed);
+ }
+ }
+ if (fileElement.equals(input.getRight())) {
+ if (changed && cmv.internalIsRightDirty())
+ setDirty(changed);
+ else if (!changed && !cmv.internalIsRightDirty()) {
+ setDirty(changed);
+ }
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#hashCode()
+ */
+ @Override
+ public int hashCode() {
+ if (document != null) {
+ return document.hashCode();
+ }
+ return input.hashCode();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+
+ if (!(obj instanceof Saveable))
+ return false;
+
+ if (document != null) {
+ Object otherDocument = ((Saveable) obj).getAdapter(IDocument.class);
+
+ if (document == null && otherDocument == null)
+ return false;
+
+ return document != null && document.equals(otherDocument);
+ }
+
+ if (obj instanceof LocalFileSaveable) {
+ LocalFileSaveable saveable = (LocalFileSaveable) obj;
+ return saveable.input.equals(input);
+ }
+ return false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.Saveable#getAdapter(java.lang.Class)
+ */
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (adapter == IDocument.class) {
+ if (document != null)
+ return document;
+ if (fileElement.isConnected()) {
+ ISharedDocumentAdapter sda = (ISharedDocumentAdapter) fileElement
+ .getAdapter(ISharedDocumentAdapter.class);
+ if (sda != null) {
+ IEditorInput input = sda.getDocumentKey(fileElement);
+ if (input != null) {
+ IDocumentProvider provider = SharedDocumentAdapter
+ .getDocumentProvider(input);
+ if (provider != null)
+ return provider.getDocument(input);
+ }
+ }
+ }
+ }
+ if (adapter == IEditorInput.class) {
+ return fileElement.getEditorInput();
+ }
+ return super.getAdapter(adapter);
+ }
+
+ /**
+ * Get an ISaveablesLifecycleListener from the specified workbench
+ * part.
+ * @param part The workbench part.
+ * @return The listener.
+ */
+ private ISaveablesLifecycleListener getSaveablesLifecycleListener(
+ IWorkbenchPart part) {
+ if (part instanceof ISaveablesLifecycleListener)
+ return (ISaveablesLifecycleListener) part;
+
+ Object adapted = part.getAdapter(ISaveablesLifecycleListener.class);
+ if (adapted instanceof ISaveablesLifecycleListener)
+ return (ISaveablesLifecycleListener) adapted;
+
+ adapted = Platform.getAdapterManager().loadAdapter(part,
+ ISaveablesLifecycleListener.class.getName());
+ if (adapted instanceof ISaveablesLifecycleListener)
+ return (ISaveablesLifecycleListener) adapted;
+
+ return (ISaveablesLifecycleListener) part.getSite().getService(
+ ISaveablesLifecycleListener.class);
+ }
+
+ /**
+ * When the document of the local file is connected, register this saveable.
+ */
+ private void registerSaveable() {
+ ICompareContainer container = editorInput.getContainer();
+ IWorkbenchPart part = container.getWorkbenchPart();
+ if (part != null) {
+ ISaveablesLifecycleListener lifecycleListener = getSaveablesLifecycleListener(part);
+ // Remove this saveable from the lifecycle listener
+ lifecycleListener.handleLifecycleEvent(new SaveablesLifecycleEvent(
+ part, SaveablesLifecycleEvent.POST_CLOSE,
+ new Saveable[] { this }, false));
+ // Now fix the hashing so it uses the fConnected fDocument
+ IDocument document = (IDocument) getAdapter(IDocument.class);
+ if (document != null) {
+ this.document = document;
+ }
+ // Finally, add this saveable back to the listener
+ lifecycleListener.handleLifecycleEvent(new SaveablesLifecycleEvent(
+ part, SaveablesLifecycleEvent.POST_OPEN,
+ new Saveable[] { this }, false));
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener#handleDocumentConnected()
+ */
+ @Override
+ public void handleDocumentConnected() {
+ if (connected)
+ return;
+ connected = true;
+ registerSaveable();
+ fileElement.setDocumentListener(null);
+ }
+
+ @Override
+ public void handleDocumentDeleted() {
+ // Ignore
+ }
+
+ @Override
+ public void handleDocumentDisconnected() {
+ // Ignore
+ }
+
+ @Override
+ public void handleDocumentFlushed() {
+ // Ignore
+ }
+
+ @Override
+ public void handleDocumentSaved() {
+ // Ignore
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.compare.IContentChangeListener#contentChanged(org.eclipse.compare.IContentChangeNotifier)
+ */
+ @Override
+ public void contentChanged(IContentChangeNotifier source) {
+ if (!saving) {
+ try {
+ performSave(new NullProgressMonitor());
+ } catch (CoreException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void doSave(IProgressMonitor monitor) throws CoreException {
+ if (isDirty()) {
+ performSave(monitor);
+ setDirty(false);
+ }
+ }
+
+ /**
+ * Revert any changes in the buffer back to the last saved state.
+ *
+ * @param monitor
+ * a progress monitor on <code>null</code> if progress feedback
+ * is not required
+ */
+ public void doRevert(IProgressMonitor monitor) {
+ if (!isDirty())
+ return;
+ fileElement.discardBuffer();
+ setDirty(false);
+ }
+
+ /**
+ * Add a property change listener. Adding a listener that is already
+ * registered has no effect.
+ *
+ * @param listener
+ * the listener
+ */
+ public void addPropertyListener(IPropertyListener listener) {
+ listeners.add(listener);
+ }
+
+ /**
+ * Remove a property change listener. Removing a listener that is not
+ * registered has no effect.
+ *
+ * @param listener
+ * the listener
+ */
+ public void removePropertyListener(IPropertyListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Fire a property change event for this buffer.
+ *
+ * @param property
+ * the property that changed
+ */
+ protected void firePropertyChange(final int property) {
+ Object[] allListeners = listeners.getListeners();
+ for (int i = 0; i < allListeners.length; i++) {
+ final Object object = allListeners[i];
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void run() throws Exception {
+ ((IPropertyListener) object).propertyChanged(
+ LocalFileSaveable.this, property);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // handled by platform
+ }
+ });
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalTypedElement.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalTypedElement.java
new file mode 100644
index 000000000..fe6c66ec3
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/LocalTypedElement.java
@@ -0,0 +1,306 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.compare.IEditableContent;
+import org.eclipse.compare.ISharedDocumentAdapter;
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.core.filesystem.EFS;
+import org.eclipse.core.filesystem.IFileStore;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.IPath;
+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.tm.te.tcf.filesystem.activator.UIPlugin;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.CacheManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.ide.FileStoreEditorInput;
+
+/**
+ * A <code>LocalTypedElement</code> extends <code>MergeTypedElement</code> and
+ * wraps an <code>FSTreeNode</code> so that it can be used as the left element
+ * of a <code>MergeEditorInput</code>. It implements the interface
+ * <code>IEditableContent</code> so that it is editable.
+ */
+public class LocalTypedElement extends MergeTypedElement implements
+ IEditableContent, IAdaptable, ISharedDocumentAdapterListener {
+ // If the current edited file is dirty.
+ private boolean dirty;
+ // The shared document adapter
+ private EditableSharedDocumentAdapter documentAdapter;
+ // The shared document listener.
+ private ISharedDocumentAdapterListener documentListener;
+
+ /**
+ * Creates a <code>LocalTypedElement</code> for the given resource.
+ *
+ * @param resource
+ * the resource
+ */
+ public LocalTypedElement(FSTreeNode node) {
+ super(node);
+ setContent(getContent());
+ dirty = false;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+ */
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (adapter == ISharedDocumentAdapter.class) {
+ if (documentAdapter == null)
+ documentAdapter = new EditableSharedDocumentAdapter(this);
+ return documentAdapter;
+ }
+ return Platform.getAdapterManager().getAdapter(this, adapter);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.BufferedContent#setContent(byte[])
+ */
+ @Override
+ public void setContent(byte[] contents) {
+ dirty = true;
+ super.setContent(contents);
+ }
+
+ /**
+ * Set the document listener.
+ *
+ * @param documentListener
+ * the document listener.
+ */
+ public void setDocumentListener(
+ ISharedDocumentAdapterListener documentListener) {
+ this.documentListener = documentListener;
+ }
+
+ /**
+ * Return an input stream that opens that locally cached file to provide the
+ * content.
+ *
+ * @return a buffered input stream containing the contents of this file
+ * @exception CoreException
+ * if the contents of this storage could not be accessed
+ */
+ @Override
+ protected InputStream createStream() throws CoreException {
+ try {
+ IPath cachePath = CacheManager.getInstance().getCachePath(node);
+ File cacheFile = cachePath.toFile();
+ return new BufferedInputStream(new FileInputStream(cacheFile));
+ } catch (FileNotFoundException e) {
+ IStatus error = new Status(IStatus.ERROR,
+ UIPlugin.getUniqueIdentifier(), e.getLocalizedMessage(), e);
+ throw new CoreException(error);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.IEditableContent#isEditable()
+ */
+ @Override
+ public boolean isEditable() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.IEditableContent#replace(org.eclipse.compare.ITypedElement, org.eclipse.compare.ITypedElement)
+ */
+ @Override
+ public ITypedElement replace(ITypedElement dest, ITypedElement src) {
+ return dest;
+ }
+
+ /**
+ * Save the shared document for this element. The save can only be performed
+ * if the element is connected to a shared document. If the element is not
+ * connected, <code>false</code> is returned.
+ *
+ * @param overwrite
+ * indicates whether overwrite should be performed while saving
+ * the given element if necessary
+ * @param monitor
+ * a progress monitor
+ * @throws CoreException
+ */
+ public boolean store2Document(IProgressMonitor monitor)
+ throws CoreException {
+ if (isConnected()) {
+ IEditorInput input = documentAdapter.getDocumentKey(this);
+ documentAdapter.saveDocument(input, monitor);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Judges whether the content has been changed.
+ *
+ * @return
+ */
+ public boolean isDirty() {
+ return dirty
+ || (documentAdapter != null && documentAdapter
+ .hasBufferedContents());
+ }
+
+ /**
+ * Set the dirty state.
+ *
+ * @param dirty
+ * The dirty state.
+ */
+ public void setDirty(boolean dirty) {
+ this.dirty = dirty;
+ }
+
+ /**
+ * If the document adapter has been connected.
+ *
+ * @return true if it is not null and connected.
+ */
+ public boolean isConnected() {
+ return documentAdapter != null && documentAdapter.isConnected();
+ }
+
+ /**
+ * Return the path to the local file of this node. It is used to compute its
+ * hash code and as the title of the comparison editor.
+ */
+ @Override
+ public String toString() {
+ File cacheFile = CacheManager.getInstance().getCacheFile(node);
+ return cacheFile.toString();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener#handleDocumentConnected()
+ */
+ @Override
+ public void handleDocumentConnected() {
+ if (documentListener != null)
+ documentListener.handleDocumentConnected();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener#handleDocumentDeleted()
+ */
+ @Override
+ public void handleDocumentDeleted() {
+ if (documentListener != null)
+ documentListener.handleDocumentDeleted();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener#handleDocumentDisconnected()
+ */
+ @Override
+ public void handleDocumentDisconnected() {
+ if (documentListener != null)
+ documentListener.handleDocumentDisconnected();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener#handleDocumentFlushed()
+ */
+ @Override
+ public void handleDocumentFlushed() {
+ fireContentChanged();
+ if (documentListener != null)
+ documentListener.handleDocumentFlushed();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.tcf.filesystem.internal.compare.EditableSharedDocumentAdapter.ISharedDocumentAdapterListener#handleDocumentSaved()
+ */
+ @Override
+ public void handleDocumentSaved() {
+ if (documentListener != null)
+ documentListener.handleDocumentSaved();
+ }
+
+ /**
+ * Get an editor input for this file.
+ *
+ * @return The editor input.
+ */
+ public IEditorInput getEditorInput() {
+ IPath path = CacheManager.getInstance().getCachePath(node);
+ IFileStore fileStore = EFS.getLocalFileSystem().getStore(path);
+ return new FileStoreEditorInput(fileStore);
+ }
+
+ /**
+ * Save to its local file when the document has not been connected yet.
+ *
+ * @param monitor
+ * The monitor that reports the progress.
+ */
+ public void store2Cache(IProgressMonitor monitor) throws CoreException {
+ File cacheFile = CacheManager.getInstance().getCacheFile(node);
+ monitor.beginTask(Messages.LocalTypedElement_SavingFile + cacheFile.getName(), 100);
+ InputStream is = getContents();
+ BufferedOutputStream bos = null;
+ try {
+ long total = cacheFile.length();
+ bos = new BufferedOutputStream(new FileOutputStream(cacheFile));
+ byte[] data = new byte[10 * 1024];
+ int length;
+ long current = 0;
+ int currProgress = 0;
+ while ((length = is.read(data)) > 0) {
+ bos.write(data, 0, length);
+ bos.flush();
+ current += length;
+ int progress = (int) (current * 100 / total);
+ if (currProgress != progress) {
+ monitor.worked(progress - currProgress);
+ currProgress = progress;
+ }
+ }
+ setDirty(false);
+ } catch (IOException e) {
+ throw new CoreException(new Status(IStatus.ERROR,
+ UIPlugin.getUniqueIdentifier(), e.getLocalizedMessage(), e));
+ } finally {
+ if (is != null)
+ try {
+ is.close();
+ } catch (IOException ex) {
+ }
+ if (bos != null) {
+ try {
+ bos.close();
+ } catch (Exception e) {
+ }
+ }
+ // Notify the local file element that the document has changed.
+ fireContentChanged();
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeEditorInput.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeEditorInput.java
new file mode 100644
index 000000000..5358126ea
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeEditorInput.java
@@ -0,0 +1,408 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.compare.CompareConfiguration;
+import org.eclipse.compare.CompareEditorInput;
+import org.eclipse.compare.IPropertyChangeNotifier;
+import org.eclipse.compare.structuremergeviewer.Differencer;
+import org.eclipse.compare.structuremergeviewer.ICompareInput;
+import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.osgi.util.TextProcessor;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.activator.UIPlugin;
+import org.eclipse.tm.te.tcf.filesystem.internal.ImageConsts;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPropertyListener;
+import org.eclipse.ui.ISaveablesSource;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPartConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.Saveable;
+/**
+ * A <code>MergeEditorInput</code> is the input of a compare editor used to
+ * compare the local file and the remote file in a Target Explorer file system.
+ */
+public class MergeEditorInput extends CompareEditorInput implements
+ ISaveablesSource, IPropertyListener, ICompareInputChangeListener {
+
+ // The left element is a local file which can be editable.
+ private LocalTypedElement left;
+ // The right element is the remote file which is read only.
+ private RemoteTypedElement right;
+
+ // The active page of the current workbench.
+ private final IWorkbenchPage page;
+
+ // The current input change listener list.
+ private final ListenerList inputChangeListeners = new ListenerList(ListenerList.IDENTITY);
+ // The current saveable for the left element, i.e., the local file.
+ private LocalFileSaveable saveable;
+
+ /**
+ * Creates a new MergeEditorInput.
+ *
+ * @param left
+ * @param right
+ * @param page
+ */
+ public MergeEditorInput(LocalTypedElement left, RemoteTypedElement right, IWorkbenchPage page) {
+ super(new CompareConfiguration());
+ this.page = page;
+ this.left = left;
+ this.right = right;
+ configureCompare();
+ }
+
+ /**
+ * Configure the compare configuration using the left
+ * and right elements. Set the left and right label.
+ * Set the editable status.
+ */
+ protected void configureCompare() {
+ CompareConfiguration cc = getCompareConfiguration();
+ cc.setLeftEditable(true);
+ cc.setRightEditable(false);
+
+ String name = TextProcessor.process(left.getName());
+ String label = "Local: " + name; //$NON-NLS-1$
+ cc.setLeftLabel(label);
+
+ name = TextProcessor.process(right.toString());
+ label = "Remote: " + name; //$NON-NLS-1$
+ cc.setRightLabel(label);
+ }
+
+ /**
+ * Returns <code>true</code> if the other object is of type
+ * <code>MergeEditorInput</code> and both of their corresponding fLeft and
+ * fRight objects are identical. The content is not considered.
+ */
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+ if (obj instanceof MergeEditorInput) {
+ MergeEditorInput other = (MergeEditorInput) obj;
+ return other.left.equals(left) && other.right.equals(right);
+ }
+ return false;
+ }
+
+ /**
+ * Prepare the compare input of this editor input. This method is not
+ * intended to be overridden of extended by subclasses (but is not final for
+ * backwards compatibility reasons). The implementation of this method in
+ * this class delegates the creation of the compare input to the
+ * {@link #prepareCompareInput(IProgressMonitor)} method which subclasses
+ * must implement.
+ *
+ * @see org.eclipse.compare.CompareEditorInput#prepareInput(org.eclipse.core.runtime.IProgressMonitor)
+ */
+ @Override
+ protected Object prepareInput(IProgressMonitor monitor)
+ throws InvocationTargetException, InterruptedException {
+ right.cacheContents(monitor);
+ MergeInput input = new MergeInput(left, right);
+ setTitle(input.getName());
+ return input;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#getToolTipText()
+ */
+ @Override
+ public String getToolTipText() {
+ return "Compare " + left + " and " + right; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#getTitle()
+ */
+ @Override
+ public String getTitle() {
+ return "Compare " + left.getName() + " with Local Cache"; //$NON-NLS-1$ //$NON-NLS-2$
+ }
+
+ /**
+ * Override the super method to provide clear typed input.
+ */
+ @Override
+ public MergeInput getCompareResult() {
+ return (MergeInput) super.getCompareResult();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#handleDispose()
+ */
+ @Override
+ protected void handleDispose() {
+ super.handleDispose();
+ ICompareInput compareInput = getCompareResult();
+ if (compareInput != null)
+ compareInput.removeCompareInputChangeListener(this);
+ if(getCompareResult()!=null){
+ getSaveable().removePropertyListener(this);
+ getSaveable().dispose();
+ }
+ left.discardBuffer();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#contentsCreated()
+ */
+ @Override
+ protected void contentsCreated() {
+ super.contentsCreated();
+ if (getCompareResult() != null) {
+ getCompareResult().addCompareInputChangeListener(this);
+ getSaveable().addPropertyListener(this);
+ setDirty(getSaveable().isDirty());
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IPropertyListener#propertyChanged(java.lang.Object, int)
+ */
+ @Override
+ public void propertyChanged(Object source, int propId) {
+ if (propId == IWorkbenchPartConstants.PROP_DIRTY && getCompareResult()!=null) {
+ setDirty(getSaveable().isDirty());
+ }
+ }
+
+ /**
+ * Close the editor if it is not dirty. If it is still dirty, let the
+ * content merge viewer handle the compare input change.
+ *
+ * @param checkForUnsavedChanges
+ * whether to check for unsaved changes
+ * @return <code>true</code> if the editor was closed (note that the close
+ * may be asynchronous)
+ */
+ protected boolean closeEditor(boolean checkForUnsavedChanges) {
+ if (isSaveNeeded() && checkForUnsavedChanges) {
+ return false;
+ }
+ final IWorkbenchPage page = getPage();
+ if (page == null)
+ return false;
+
+ Runnable runnable = new Runnable() {
+ @Override
+ public void run() {
+ Shell shell = page.getWorkbenchWindow().getShell();
+ if (shell == null)
+ return;
+
+ IEditorPart part = page.findEditor(MergeEditorInput.this);
+ getPage().closeEditor(part, false);
+ }
+ };
+ if (Display.getCurrent() != null) {
+ runnable.run();
+ } else {
+ Shell shell = page.getWorkbenchWindow().getShell();
+ if (shell == null)
+ return false;
+ Display display = shell.getDisplay();
+ display.asyncExec(runnable);
+ }
+ return true;
+ }
+
+ /**
+ * Get the current active page.
+ * @return the workbench page.
+ */
+ IWorkbenchPage getPage() {
+ if (page == null)
+ return PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ return page;
+ }
+
+ /**
+ * Propagate the input change event to the compare input change listener list.
+ */
+ /* default */void propogateInputChange() {
+ if (!inputChangeListeners.isEmpty()) {
+ Object[] allListeners = inputChangeListeners.getListeners();
+ for (int i = 0; i < allListeners.length; i++) {
+ final ICompareInputChangeListener listener = (ICompareInputChangeListener) allListeners[i];
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void run() throws Exception {
+ listener.compareInputChanged(getCompareResult());
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Logged by the safe runner
+ }
+ });
+ }
+ }
+ }
+
+ /**
+ * Get the fSaveable that provides the save behavior for this compare editor
+ * input. The {@link #createSaveable()} is called to create the fSaveable if
+ * it does not yet exist. This method cannot be called until after the input
+ * is prepared (i.e. until after the {@link #run(IProgressMonitor)} method
+ * is called which will in turn will invoke
+ * {@link #prepareCompareInput(IProgressMonitor)}.
+ *
+ * @return fSaveable that provides the save behavior for this compare editor
+ * input.
+ */
+ public LocalFileSaveable getSaveable() {
+ if (saveable == null) {
+ assert getCompareResult() != null;
+ saveable = new LocalFileSaveable(getCompareResult(), this, left);
+ }
+ return saveable;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.ISaveablesSource#getActiveSaveables()
+ */
+ @Override
+ public Saveable[] getActiveSaveables() {
+ if (getCompareResult() == null)
+ return new Saveable[0];
+ return new Saveable[] { getSaveable() };
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.ISaveablesSource#getSaveables()
+ */
+ @Override
+ public Saveable[] getSaveables() {
+ return getActiveSaveables();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
+ */
+ @Override
+ public void addCompareInputChangeListener(ICompareInput input,
+ ICompareInputChangeListener listener) {
+ if (input == getCompareResult()) {
+ inputChangeListeners.add(listener);
+ } else {
+ super.addCompareInputChangeListener(input, listener);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#removeCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
+ */
+ @Override
+ public void removeCompareInputChangeListener(ICompareInput input,
+ ICompareInputChangeListener listener) {
+ if (input == getCompareResult()) {
+ inputChangeListeners.remove(listener);
+ } else {
+ super.removeCompareInputChangeListener(input, listener);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#getTitleImage()
+ */
+ @Override
+ public Image getTitleImage() {
+ return UIPlugin.getImage(ImageConsts.COMPARE_EDITOR);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#getImageDescriptor()
+ */
+ @Override
+ public ImageDescriptor getImageDescriptor() {
+ return UIPlugin.getImageDescriptor(ImageConsts.COMPARE_EDITOR);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#findContentViewer(org.eclipse.jface.viewers.Viewer, org.eclipse.compare.structuremergeviewer.ICompareInput, org.eclipse.swt.widgets.Composite)
+ */
+ @Override
+ public Viewer findContentViewer(Viewer oldViewer, ICompareInput input,
+ Composite parent) {
+ Viewer newViewer = super.findContentViewer(oldViewer, input, parent);
+ boolean isNewViewer = newViewer != oldViewer;
+ if (isNewViewer && newViewer instanceof IPropertyChangeNotifier && getCompareResult()!=null) {
+ // Register the model for change events if appropriate
+ final IPropertyChangeNotifier dsp = (IPropertyChangeNotifier) newViewer;
+ dsp.addPropertyChangeListener(getSaveable());
+ Control c = newViewer.getControl();
+ c.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ dsp.removePropertyChangeListener(getSaveable());
+ }
+ });
+ }
+ return newViewer;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#canRunAsJob()
+ */
+ @Override
+ public boolean canRunAsJob() {
+ return true;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.CompareEditorInput#isDirty()
+ */
+ @Override
+ public boolean isDirty() {
+ if (saveable != null)
+ return saveable.isDirty();
+ return super.isDirty();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener#compareInputChanged(org.eclipse.compare.structuremergeviewer.ICompareInput)
+ */
+ @Override
+ public void compareInputChanged(ICompareInput source) {
+ if (source == getCompareResult()) {
+ boolean closed = false;
+ if (source.getKind() == Differencer.NO_CHANGE) {
+ closed = closeEditor(true);
+ }
+ if (!closed) {
+ // The editor was closed either because the compare
+ // input still has changes or because the editor input
+ // is dirty. In either case, fire the changes
+ // to the registered listeners
+ propogateInputChange();
+ }
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeInput.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeInput.java
new file mode 100644
index 000000000..3d461e840
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeInput.java
@@ -0,0 +1,158 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.compare.structuremergeviewer.Differencer;
+import org.eclipse.compare.structuremergeviewer.ICompareInput;
+import org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener;
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.ISafeRunnable;
+import org.eclipse.core.runtime.ListenerList;
+import org.eclipse.core.runtime.SafeRunner;
+import org.eclipse.swt.graphics.Image;
+
+/**
+ * An abstract compare input whose purpose is to support change notification
+ * through a {@link CompareInputChangeNotifier}.
+ */
+public class MergeInput implements ICompareInput {
+
+ // The left element.
+ private ITypedElement left;
+ // The right element.
+ private ITypedElement right;
+ // The compare input change listener list.
+ private final ListenerList listeners = new ListenerList(ListenerList.IDENTITY);
+
+ /**
+ * Create a <code>MergeInput</code>.
+ * @param left the left element.
+ * @param right the right element.
+ */
+ public MergeInput(ITypedElement left, ITypedElement right) {
+ this.left = left;
+ this.right = right;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#addCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
+ */
+ @Override
+ public void addCompareInputChangeListener(ICompareInputChangeListener listener) {
+ listeners.add(listener);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#removeCompareInputChangeListener(org.eclipse.compare.structuremergeviewer.ICompareInputChangeListener)
+ */
+ @Override
+ public void removeCompareInputChangeListener(ICompareInputChangeListener listener) {
+ listeners.remove(listener);
+ }
+
+ /**
+ * Fire a compare input change event. This method must be called from the UI
+ * thread.
+ */
+ void fireInputChanged() {
+ if (!listeners.isEmpty()) {
+ Object[] _listeners = listeners.getListeners();
+ for (int i = 0; i < _listeners.length; i++) {
+ final ICompareInputChangeListener listener = (ICompareInputChangeListener) _listeners[i];
+ SafeRunner.run(new ISafeRunnable() {
+ @Override
+ public void run() throws Exception {
+ listener.compareInputChanged(MergeInput.this);
+ }
+
+ @Override
+ public void handleException(Throwable exception) {
+ // Logged by the safe runner
+ }
+ });
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#copy(boolean)
+ */
+ @Override
+ public void copy(boolean leftToRight) {
+ Assert.isTrue(false, "Copy is not support by this type of compare input"); //$NON-NLS-1$
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#getAncestor()
+ */
+ @Override
+ public ITypedElement getAncestor() {
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#getImage()
+ */
+ @Override
+ public Image getImage() {
+ ITypedElement element = getMainElement();
+ return element == null ? null : element.getImage();
+ }
+
+ /**
+ * Return the main non-null element that identifies this input. By default,
+ * the fLeft is returned if non-null. If the fLeft is null, the fRight is
+ * returned. If both the fLeft and fRight are null the ancestor is returned.
+ *
+ * @return the main non-null element that identifies this input
+ */
+ private ITypedElement getMainElement() {
+ if (left != null)
+ return left;
+ if (right != null)
+ return right;
+ return null;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#getKind()
+ */
+ @Override
+ public int getKind() {
+ return Differencer.CHANGE;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#getLeft()
+ */
+ @Override
+ public ITypedElement getLeft() {
+ return left;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#getName()
+ */
+ @Override
+ public String getName() {
+ ITypedElement element = getMainElement();
+ return element == null ? null : element.getName();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.structuremergeviewer.ICompareInput#getRight()
+ */
+ @Override
+ public ITypedElement getRight() {
+ return right;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeTypedElement.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeTypedElement.java
new file mode 100644
index 000000000..8eaf73b3c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/MergeTypedElement.java
@@ -0,0 +1,100 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import org.eclipse.compare.BufferedContent;
+import org.eclipse.compare.CompareUI;
+import org.eclipse.compare.ITypedElement;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+
+/**
+ * A <code>MergeTypedElement</code> wraps an <code>FSTreeNode</code> so that it
+ * can be used as input for the differencing engine (<code>ITypedElement</code>).
+ */
+public abstract class MergeTypedElement extends BufferedContent implements ITypedElement {
+ // The File System tree node to be wrapped.
+ protected FSTreeNode node;
+
+ /**
+ * Create a MergeTypedElement for the given node.
+ *
+ * @param node
+ * The node.
+ */
+ public MergeTypedElement(FSTreeNode node) {
+ this.node = node;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.ITypedElement#getImage()
+ */
+ @Override
+ public Image getImage() {
+ return CompareUI.getImage(getType());
+ }
+
+ /**
+ * Return the tree node wrapped.
+ *
+ * @return The tree node of the file
+ */
+ public FSTreeNode getFSTreeNode() {
+ return node;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.ITypedElement#getType()
+ */
+ @Override
+ public String getType() {
+ if (node.isDirectory())
+ return ITypedElement.FOLDER_TYPE;
+ if (node != null) {
+ String s = node.name;
+ int dot = s.lastIndexOf('.');
+ if (dot != -1)
+ s = s.substring(dot + 1);
+ if (s != null)
+ return s;
+ }
+ return ITypedElement.UNKNOWN_TYPE;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#equals(java.lang.Object)
+ */
+ @Override
+ public boolean equals(Object other) {
+ if (other instanceof ITypedElement) {
+ return toString().equals(other.toString());
+ }
+ return super.equals(other);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.compare.ITypedElement#getName()
+ */
+ @Override
+ public String getName() {
+ return node.name;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Object#hashCode()
+ *
+ * Returns the hash code of the name.
+ */
+ @Override
+ public int hashCode() {
+ return toString().hashCode();
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/RemoteTypedElement.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/RemoteTypedElement.java
new file mode 100644
index 000000000..75d543537
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/compare/RemoteTypedElement.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.compare;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.InvocationTargetException;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tm.te.tcf.filesystem.activator.UIPlugin;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.CacheManager;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+
+/**
+ * A <code>RemoteTypedElement</code> wraps an <code>FSTreeNode</code> so that it
+ * can be used as input for the differencing engine (<code>ITypedElement</code>)
+ * as the right element of the comparison editor.
+ *
+ * @since 3.7
+ */
+public class RemoteTypedElement extends MergeTypedElement {
+ /**
+ * Creates a <code>RemoteTypedElement</code> for the given node.
+ *
+ * @param node
+ * the tree node.
+ */
+ public RemoteTypedElement(FSTreeNode node) {
+ super(node);
+ }
+
+ /**
+ * Return an input stream that opens that remote file to provide the stream
+ * content.
+ *
+ * @return a buffered input stream containing the contents of this file
+ * @exception CoreException
+ * if the contents of this storage could not be accessed
+ */
+ @Override
+ protected InputStream createStream() throws CoreException {
+ try {
+ return node.getLocationURL().openStream();
+ } catch (IOException e) {
+ Status error = new Status(IStatus.ERROR,
+ UIPlugin.getUniqueIdentifier(), e.getLocalizedMessage(), e);
+ throw new CoreException(error);
+ }
+ }
+
+ /**
+ * Download the remote file and save the content so that it is cached for
+ * getContents call.
+ *
+ * @param monitor
+ * The monitor used to display downloading progress.
+ * @throws InvocationTargetException
+ * throws when an exception occurs during downloading.
+ */
+ public void cacheContents(IProgressMonitor monitor)
+ throws InvocationTargetException {
+ monitor.beginTask(
+ NLS.bind(Messages.CacheManager_DowloadingFile, node.name), 100);
+ OutputStream output = null;
+ try {
+ final ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ output = new BufferedOutputStream(baos);
+ monitor.beginTask(Messages.RemoteTypedElement_GettingRemoteContent
+ + node.name, 100);
+ CacheManager.getInstance().download2OutputStream(node, output, monitor);
+ if (!monitor.isCanceled()) {
+ setContent(baos.toByteArray());
+ }
+ } catch (IOException e) {
+ throw new InvocationTargetException(e);
+ }
+ }
+
+ /**
+ * Return the external form of the URL to the remote file of this node. It
+ * is used to compute its hash code and as the title of the comparison
+ * editor.
+ */
+ @Override
+ public String toString() {
+ return node.getLocationURL().toString();
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/events/INodeStateListener.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/events/INodeStateListener.java
new file mode 100644
index 000000000..9790e841d
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/events/INodeStateListener.java
@@ -0,0 +1,26 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.events;
+
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+/**
+ * An INodeStateListener is a listener interface. Classes that implement this
+ * interface serve as a listener processing the event that a node state has changed.
+ *
+ */
+public interface INodeStateListener {
+ /**
+ * Fired when the state of the specified FSTreeNode has changed.
+ *
+ * @param node The FSTreeNode whose state has changed.
+ */
+ void stateChanged(FSTreeNode node);
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFChannelException.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFChannelException.java
new file mode 100644
index 000000000..e8e22d6b5
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFChannelException.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.exceptions;
+
+/**
+ * TCF channel exception.
+ */
+public class TCFChannelException extends TCFException {
+ private static final long serialVersionUID = 7414816212710485160L;
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * The exception detail message or <code>null</code>.
+ */
+ public TCFChannelException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * The exception detail message or <code>null</code>.
+ * @param cause
+ * The exception cause or <code>null</code>.
+ */
+ public TCFChannelException(String message, Throwable cause){
+ super(message, cause);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFException.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFException.java
new file mode 100644
index 000000000..40d5a3523
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFException.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.exceptions;
+
+/**
+ * TCF file system implementation base exception.
+ */
+public class TCFException extends Exception {
+ private static final long serialVersionUID = -220092425137980661L;
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * The exception detail message or <code>null</code>.
+ */
+ public TCFException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * The exception detail message or <code>null</code>.
+ * @param cause
+ * The exception cause or <code>null</code>.
+ */
+ public TCFException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFFileSystemException.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFFileSystemException.java
new file mode 100644
index 000000000..7b5edac15
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/exceptions/TCFFileSystemException.java
@@ -0,0 +1,41 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.exceptions;
+
+/**
+ * TCF remote file system exception.
+ */
+public class TCFFileSystemException extends TCFException {
+ private static final long serialVersionUID = -5203855887734608373L;
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * The exception detail message or <code>null</code>.
+ */
+ public TCFFileSystemException(String message) {
+ super(message);
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param message
+ * The exception detail message or <code>null</code>.
+ * @param cause
+ * The exception cause or <code>null</code>.
+ */
+ public TCFFileSystemException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CacheManager.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CacheManager.java
index 2332963d1..9d2869cc9 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CacheManager.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CacheManager.java
@@ -6,45 +6,68 @@
*
* Contributors:
* Wind River Systems - initial API and implementation
- * William Chen (Wind River)- [345387]Open the remote files with a proper editor
+ * William Chen (Wind River)- [345387] Open the remote files with a proper editor
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
+import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.text.DecimalFormat;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
+import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.tm.te.tcf.filesystem.activator.UIPlugin;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.internal.preferences.TargetExplorerPreferencePage;
+import org.eclipse.tm.te.tcf.filesystem.internal.url.TcfURLConnection;
import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.PlatformUI;
/**
* The local file system cache used to manage the temporary files downloaded
* from a remote file system.
*/
public class CacheManager {
+
+ // Time stamp file used to persist the time stamps of each file.
+ private static final String TIMESTAMP_FILE = "timestamps.xml"; //$NON-NLS-1$
+
+ // The agent directory's prefixed name.
private static final String WS_AGENT_DIR_PREFIX = "agent_"; //$NON-NLS-1$
- // The singleton instance.
- private static CacheManager instance;
- // The formatter used to format the size displayed while downloading.
- private static DecimalFormat SIZE_FORMAT = new DecimalFormat("#,##0.##"); //$NON-NLS-1$
// The default chunk size of the buffer used during downloading files.
private static final int DEFAULT_CHUNK_SIZE = 5 * 1024;
+ // The formatter used to format the size displayed while downloading.
+ private static final DecimalFormat SIZE_FORMAT = new DecimalFormat("#,##0.##"); //$NON-NLS-1$
+
+ // The singleton instance.
+ private static CacheManager instance;
+
+ // The time stamp for each file.
+ private Map<URL, Long> timestamps;
+
/**
* Get the singleton cache manager.
*
@@ -58,32 +81,133 @@ public class CacheManager {
}
/**
+ * Create a cache manager.
+ */
+ private CacheManager() {
+ loadTimestamps();
+ }
+
+ /**
+ * If the option of "autosaving" is set to on.
+ *
+ * @return true if it is auto saving or else false.
+ */
+ public boolean isAutoSaving(){
+ IPreferenceStore preferenceStore = UIPlugin.getDefault().getPreferenceStore();
+ boolean autoSaving = preferenceStore.getBoolean(TargetExplorerPreferencePage.PREF_AUTOSAVING);
+ return autoSaving;
+ }
+
+ /**
+ * Load the time stamps from the time stamps file in the cache's root directory.
+ */
+ private void loadTimestamps() {
+ timestamps = Collections.synchronizedMap(new HashMap<URL, Long>());
+ File location = getCacheRoot();
+ File tsFile = new File(location, TIMESTAMP_FILE);
+ if (tsFile.exists()) {
+ Properties properties = new Properties();
+ InputStream input = null;
+ try {
+ input = new BufferedInputStream(new FileInputStream(tsFile));
+ properties.loadFromXML(input);
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ if (input != null) {
+ try {
+ input.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ Enumeration<String> keys = (Enumeration<String>) properties.propertyNames();
+ while (keys.hasMoreElements()) {
+ String key = keys.nextElement();
+ String value = properties.getProperty(key);
+ long timestamp = 0L;
+ try {
+ timestamp = Long.parseLong(value);
+ timestamps.put(new URL(key), Long.valueOf(timestamp));
+ } catch (Exception nfe) {
+ }
+ }
+ }
+ }
+
+ /**
+ * Save the time stamps to the time stamps file.
+ */
+ private void saveTimestamps(){
+ Properties properties = new Properties();
+ for(URL key:timestamps.keySet()){
+ Long timestamp = timestamps.get(key);
+ properties.setProperty(key.toString(), timestamp.toString());
+ }
+ File location = getCacheRoot();
+ File fTimestamp = new File(location, TIMESTAMP_FILE);
+ OutputStream output = null;
+ try{
+ output = new BufferedOutputStream(new FileOutputStream(fTimestamp));
+ properties.storeToXML(output, null);
+ }catch(IOException e){
+ e.printStackTrace();
+ }finally{
+ if(output!=null){
+ try{
+ output.close();
+ }catch(Exception e){}
+ }
+ }
+ }
+
+ /**
+ * Set the time stamp of the FSTreeNode with the specified location.
+ * @param url The FSTreeNode's location URL.
+ * @param timestamp The new base time stamp to be set.
+ */
+ public void setBaseTimestamp(URL url, long timestamp){
+ timestamps.put(url, Long.valueOf(timestamp));
+ // Persist as well.
+ saveTimestamps();
+ }
+
+ /**
+ * Remove the time stamp entry with the specified URL.
+ * @param url The URL key.
+ */
+ public void removeBaseTimestamp(URL url){
+ timestamps.remove(url);
+ // Persist
+ saveTimestamps();
+ }
+
+ /**
+ * Get the time stamp of the FSTreeNode with the specified location.
+ *
+ * @param url The FSTreeNode's location URL.
+ * @return The FSTreeNode's base time stamp.
+ */
+ public long getBaseTimestamp(URL url){
+ Long timestamp = timestamps.get(url);
+ return timestamp == null ? 0L : timestamp.longValue();
+ }
+
+ /**
* Get the local path of a node's cached file.
* <p>
* The preferred location is within the plugin's state location, in
* example <code>&lt;state location&gt;agent_<hashcode_of_peerId>/remote/path/to/the/file...</code>.
* <p>
- * If the plugin is loaded in a RCP workspace-less environment, the
- * fallback strategy is to use the users home directory.
+ * If the plug-in is loaded in a RCP workspace-less environment, the
+ * fall back strategy is to use the users home directory.
*
* @param node
* The file/folder node.
* @return The local path of the node's cached file.
*/
public IPath getCachePath(FSTreeNode node) {
- File location;
- try {
- location = UIPlugin.getDefault().getStateLocation().toFile();
- }
- catch (IllegalStateException e) {
- // An RCP workspace-less environment (-data @none)
- location = new File(System.getProperty("user.home"), ".tcf"); //$NON-NLS-1$ //$NON-NLS-2$
- location = new File(location, "fs"); //$NON-NLS-1$
- }
-
- // Create the location if it not exist
- if (!location.exists()) location.mkdir();
-
+ File location = getCacheRoot();
String agentId = node.peerNode.getPeer().getID();
// Use Math.abs to avoid negative hash value.
String agent = WS_AGENT_DIR_PREFIX + Math.abs(agentId.hashCode());
@@ -92,11 +216,49 @@ public class CacheManager {
if (!agentDirFile.exists()) {
agentDirFile.mkdir();
}
-
return appendNodePath(agentDir, node);
}
/**
+ * Get the local file of the specified node.
+ *
+ * <p>
+ * The preferred location is within the plugin's state location, in
+ * example <code>&lt;state location&gt;agent_<hashcode_of_peerId>/remote/path/to/the/file...</code>.
+ * <p>
+ * If the plug-in is loaded in a RCP workspace-less environment, the
+ * fall back strategy is to use the users home directory.
+ *
+ * @param node
+ * The file/folder node.
+ * @return The file object of the node's local cache.
+ */
+ public File getCacheFile(FSTreeNode node){
+ return getCachePath(node).toFile();
+ }
+
+ /**
+ * Get the cache file system's root directory on the local host's
+ * file system.
+ *
+ * @return The root folder's location of the cache file system.
+ */
+ private File getCacheRoot() {
+ File location;
+ try {
+ location = UIPlugin.getDefault().getStateLocation().toFile();
+ }catch (IllegalStateException e) {
+ // An RCP workspace-less environment (-data @none)
+ location = new File(System.getProperty("user.home"), ".tcf"); //$NON-NLS-1$ //$NON-NLS-2$
+ location = new File(location, "fs"); //$NON-NLS-1$
+ }
+
+ // Create the location if it not exist
+ if (!location.exists()) location.mkdir();
+ return location;
+ }
+
+ /**
* Append the path with the specified node's context path.
*
* @param path
@@ -106,7 +268,7 @@ public class CacheManager {
* @return The path to the node.
*/
private IPath appendNodePath(IPath path, FSTreeNode node) {
- if (!node.isRoot()) {
+ if (!node.isRoot() && node.parent!=null) {
path = appendNodePath(path, node.parent);
return appendPathSegment(node, path, node.name);
}
@@ -124,7 +286,7 @@ public class CacheManager {
* @param node The file/folder node.
* @param path The path to appended.
* @param name The segment's name.
- * @return
+ * @return The path with the segment "name" appended.
*/
private IPath appendPathSegment(FSTreeNode node, IPath path, String name) {
IPath newPath = path.append(name);
@@ -136,75 +298,116 @@ public class CacheManager {
}
/**
- * Get the cache file's staleness. If the cache file does not exist or the
- * file is already out-dated, then return true.
- * <p>
- * When a local cache file is created, the modified time is set to that of
- * its remote corresponding file. So if its remote file is changed, the
- * modified time stamp should be different from the local cache file's
- * modified time stamp.
- * <p>
- * See the method "download" for more details.
- * <p>
- *
- * @param node
- * The file/folder node.
- * @return true if the file doesn't exist or it is stale.
- */
- public boolean isCacheStale(FSTreeNode node) {
- IPath path = getCachePath(node);
- File file = path.toFile();
- return !file.exists() || file.lastModified() != node.attr.mtime;
- }
-
- /**
* Download the data of the file from the remote file system.
- *
+ * Must be called within a UI thread.
* @param node
* The file node.
- * @param parent
- * The shell parent used to display messages.
*
* @return true if it is successful, false there're errors or it is
* canceled.
*/
- public boolean download(final FSTreeNode node, Shell parent) {
+ public boolean download(final FSTreeNode node) {
IRunnableWithProgress runnable = new IRunnableWithProgress() {
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
monitor.beginTask(NLS.bind(Messages.CacheManager_DowloadingFile, node.name), 100);
+ OutputStream output = null;
try {
- boolean canceled = downloadFile(node, monitor);
- if (canceled)
+ // Write the data to its local cache file.
+ File file = getCachePath(node).toFile();
+ if(file.exists() && !file.canWrite()){
+ // If the file exists and is read-only, delete it.
+ file.delete();
+ }
+ output = new BufferedOutputStream(new FileOutputStream(file));
+ download2OutputStream(node, output, monitor);
+ if (monitor.isCanceled())
throw new InterruptedException();
} catch (IOException e) {
throw new InvocationTargetException(e);
} finally {
+ if (output != null) {
+ try {
+ output.close();
+ } catch (Exception e) {
+ }
+ }
monitor.done();
}
}
};
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
TimeTriggeredProgressMonitorDialog dialog = new TimeTriggeredProgressMonitorDialog(
parent, 250);
dialog.setCancelable(true);
File file = getCachePath(node).toFile();
try {
dialog.run(true, true, runnable);
- // If downloading is successful, set the last modified time to
- // that of its corresponding file.
- file.setLastModified(node.attr.mtime);
+ // If downloading is successful, update the attributes of the file and
+ // set the last modified time to that of its corresponding file.
+ StateManager.getInstance().updateState(node);
// If the node is read-only, make the cache file read-only.
if(!node.isWritable())
file.setReadOnly();
return true;
+ } catch(TCFException e) {
+ MessageDialog.openError(parent, Messages.StateManager_UpdateFailureTitle, e.getLocalizedMessage());
} catch (InvocationTargetException e) {
// Something's gone wrong. Roll back the downloading and display the
// error.
file.delete();
- displayError(node, parent, e);
+ removeBaseTimestamp(node.getLocationURL());
+ displayError(parent, e);
} catch (InterruptedException e) {
// It is canceled. Just roll back the downloading result.
file.delete();
+ removeBaseTimestamp(node.getLocationURL());
+ }
+ return false;
+ }
+
+ /**
+ * Upload the local files to the remote file system.
+ * Must be called within UI thread.
+ * @param nodes
+ * The files' location. Not null.
+ *
+ * @return true if it is successful, false there're errors or it is
+ * canceled.
+ */
+ public boolean upload(final FSTreeNode... nodes) {
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ try {
+ IRunnableWithProgress runnable = new IRunnableWithProgress() {
+ @Override
+ public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
+ try {
+ String message;
+ if(nodes.length==1)
+ message = NLS.bind(Messages.CacheManager_UploadSingleFile, nodes[0].name);
+ else
+ message = NLS.bind(Messages.CacheManager_UploadNFiles, Long.valueOf(nodes.length));
+ monitor.beginTask(message, 100);
+ boolean canceled = uploadFiles(monitor, nodes);
+ if (canceled)
+ throw new InterruptedException();
+ } catch (Exception e) {
+ throw new InvocationTargetException(e);
+ } finally {
+ monitor.done();
+ }
+ }
+ };
+ TimeTriggeredProgressMonitorDialog dialog = new TimeTriggeredProgressMonitorDialog(parent, 250);
+ dialog.setCancelable(true);
+ dialog.run(true, true, runnable);
+ return true;
+ } catch (InvocationTargetException e) {
+ // Something's gone wrong. Roll back the downloading and display the
+ // error.
+ displayError(parent, e);
+ } catch (InterruptedException e) {
+ // It is canceled. Just roll back the downloading result.
}
return false;
}
@@ -219,40 +422,114 @@ public class CacheManager {
* @param e
* The error exception.
*/
- private void displayError(FSTreeNode node, Shell parent, InvocationTargetException e) {
+ private void displayError(Shell parent, InvocationTargetException e) {
Throwable target = e.getTargetException();
Throwable cause = target.getCause() != null ? target.getCause() : target;
MessageDialog.openError(parent, Messages.CacheManager_DownloadingError, cause.getLocalizedMessage());
}
/**
- * Download the specified file using the monitor to report the progress.
+ * Upload the specified files using the monitor to report the progress.
+ *
+ * @param peers
+ * The local files' peer files.
+ * @param locals
+ * The local files to be uploaded.
+ * @param monitor
+ * The monitor used to report the progress.
+ * @return true if it is canceled or else false.
+ * @throws Exception
+ * an Exception thrown during downloading and storing data.
+ */
+ public boolean uploadFiles(IProgressMonitor monitor, FSTreeNode... nodes) throws IOException {
+ BufferedInputStream input = null;
+ BufferedOutputStream output = null;
+ // The buffer used to download the file.
+ byte[] data = new byte[DEFAULT_CHUNK_SIZE];
+ // Calculate the total size.
+ long totalSize = 0;
+ for (FSTreeNode node : nodes) {
+ File file = getCachePath(node).toFile();
+ totalSize += file.length();
+ }
+ // Calculate the chunk size of one percent.
+ int chunk_size = (int) totalSize / 100;
+ // The current reading percentage.
+ int percentRead = 0;
+ // The current length of read bytes.
+ long bytesRead = 0;
+ for (int i = 0; i < nodes.length && !monitor.isCanceled(); i++) {
+ File file = getCachePath(nodes[i]).toFile();
+ try {
+ URL url = nodes[i].getLocationURL();
+ TcfURLConnection connection = (TcfURLConnection) url.openConnection();
+ connection.setDoInput(false);
+ connection.setDoOutput(true);
+ input = new BufferedInputStream(new FileInputStream(file));
+ output = new BufferedOutputStream(connection.getOutputStream());
+
+ // Total size displayed on the progress dialog.
+ String fileLength = formatSize(file.length());
+ int length;
+ while ((length = input.read(data)) >= 0 && !monitor.isCanceled()) {
+ output.write(data, 0, length);
+ output.flush();
+ bytesRead += length;
+ if (chunk_size != 0) {
+ int percent = (int) bytesRead / chunk_size;
+ if (percent != percentRead) { // Update the progress.
+ monitor.worked(percent - percentRead);
+ percentRead = percent; // Remember the percentage.
+ // Report the progress.
+ monitor.subTask(NLS.bind(Messages.CacheManager_UploadingProgress, new Object[]{file.getName(), formatSize(bytesRead), fileLength}));
+ }
+ }
+ }
+ } finally {
+ if (output != null) {
+ try {
+ output.close();
+ } catch (Exception e) {
+ }
+ }
+ if (input != null) {
+ try {
+ input.close();
+ } catch (Exception e) {
+ }
+ }
+ if(!monitor.isCanceled()){
+ // Once upload is successful, synchronize the modified time.
+ try {
+ StateManager.getInstance().commitState(nodes[i]);
+ } catch (TCFException tcfe) {
+ throw new IOException(tcfe.getLocalizedMessage());
+ }
+ }
+ }
+ }
+ return monitor.isCanceled();
+ }
+
+ /**
+ * Download the specified file into an output stream using the monitor to report the progress.
*
* @param node
* The file to be downloaded.
+ * @param output
+ * The output stream.
* @param monitor
* The monitor used to report the progress.
- * @return true if it is canceled or else false.
* @throws IOException
* an IOException thrown during downloading and storing data.
*/
- protected boolean downloadFile(FSTreeNode node, IProgressMonitor monitor)
- throws IOException {
- BufferedInputStream input = null;
- BufferedOutputStream output = null;
- try {
- // Open the input stream of the node using the tcf stream protocol.
+ public void download2OutputStream(FSTreeNode node, OutputStream output, IProgressMonitor monitor) throws IOException {
+ InputStream input = null;
+ // Open the input stream of the node using the tcf stream protocol.
+ try{
URL url = node.getLocationURL();
InputStream in = url.openStream();
input = new BufferedInputStream(in);
- // Write the data to its local cache file.
- File file = getCachePath(node).toFile();
- if(file.exists() && !file.canWrite()){
- // If the file exists and is read-only, delete it.
- file.delete();
- }
- output = new BufferedOutputStream(new FileOutputStream(file));
-
// The buffer used to download the file.
byte[] data = new byte[DEFAULT_CHUNK_SIZE];
// Calculate the chunk size of one percent.
@@ -277,14 +554,7 @@ public class CacheManager {
}
}
}
- return monitor.isCanceled();
- } finally {
- if (output != null) {
- try {
- output.close();
- } catch (Exception e) {
- }
- }
+ }finally{
if (input != null) {
try {
input.close();
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CachePropertyTester.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CachePropertyTester.java
new file mode 100644
index 000000000..1e8d96ebc
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CachePropertyTester.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import org.eclipse.core.expressions.PropertyTester;
+
+/**
+ * Provide a tester to test if the current auto saving mode is on or off.
+ *
+ */
+public class CachePropertyTester extends PropertyTester {
+ /**
+ * Create a cache property tester.
+ */
+ public CachePropertyTester() {
+ }
+
+ /* (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) {
+ if(property.equals("isAutoSavingOn")){ //$NON-NLS-1$
+ return CacheManager.getInstance().isAutoSaving();
+ }
+ return false;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CommitHandler.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CommitHandler.java
new file mode 100644
index 000000000..6ece7624c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/CommitHandler.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import java.io.File;
+
+import org.eclipse.compare.CompareUI;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.LocalTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.MergeEditorInput;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.RemoteTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The handler that commits the content of a modified file to the target file system.
+ */
+public class CommitHandler extends AbstractHandler {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
+ FSTreeNode node = (FSTreeNode) selection.getFirstElement();
+ try {
+ // Refresh the node to get the latest state.
+ StateManager.getInstance().refreshState(node);
+ Shell parent = HandlerUtil.getActiveShell(event);
+ File file = CacheManager.getInstance().getCacheFile(node);
+ if (file.exists()) {
+ CacheState state = StateManager.getInstance().getCacheState(node);
+ switch (state) {
+ case conflict:
+ String title = Messages.CmmitHandler_StateChangedDialogTitle;
+ String message = NLS.bind(Messages.CmmitHandler_StateChangedMessage, node.name);
+ MessageDialog msgDialog = new MessageDialog(parent, title, null, message, MessageDialog.QUESTION, new String[] { Messages.CmmitHandler_Merge, Messages.CmmitHandler_CommitAnyway,
+ Messages.CmmitHandler_Cancel }, 0);
+ int index = msgDialog.open();
+ if (index == 0) {// Merge
+ LocalTypedElement local = new LocalTypedElement(node);
+ RemoteTypedElement remote = new RemoteTypedElement(node);
+ IWorkbenchPage page = HandlerUtil.getActiveSite(event).getPage();
+ MergeEditorInput input = new MergeEditorInput(local, remote, page);
+ CompareUI.openCompareDialog(input);
+ } else if (index == 1) { // Commit anyway
+ CacheManager.getInstance().upload(node);
+ }
+ break;
+ case modified:
+ // Commit it normally.
+ CacheManager.getInstance().upload(node);
+ break;
+ case consistent:
+ break;
+ case outdated:
+ break;
+ }
+ } else {
+ String message = NLS.bind(Messages.CmmitHandler_FileDeleted, file.getName());
+ MessageDialog.openError(parent, Messages.CmmitHandler_ErrorTitle, message);
+ }
+ } catch (TCFException e) {
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MessageDialog.openError(parent, Messages.StateManager_RefreshFailureTitle, e.getLocalizedMessage());
+ }
+ return null;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/ContentTypeHelper.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/ContentTypeHelper.java
index 0ae5dcf57..a746b982e 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/ContentTypeHelper.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/ContentTypeHelper.java
@@ -9,9 +9,9 @@
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
-import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
@@ -38,10 +38,10 @@ public class ContentTypeHelper {
private Map<URL, IContentType> resolvables = new HashMap<URL, IContentType>();
// Already known unresolvable file nodes specified by their URLs.
private Map<URL, FSTreeNode> unresolvables = new HashMap<URL, FSTreeNode>();
-
+
/**
* Get the singleton instance of the content type helper.
- *
+ *
* @return The singleton instance of the content type helper.
*/
public static ContentTypeHelper getInstance() {
@@ -53,7 +53,7 @@ public class ContentTypeHelper {
/**
* Judges if the node is a binary file.
- *
+ *
* @param node
* The file node.
* @return true if the node is a binary file or else false.
@@ -71,24 +71,19 @@ public class ContentTypeHelper {
/**
* Get the content type of the specified file node.
- *
+ *
* @param node
* The file node.
* @return The content type of the file node.
*/
public IContentType getContentType(FSTreeNode node) {
- URL location = null;
- try {
- location = node.getLocationURL();
- } catch (MalformedURLException e1) {
- return null;
- }
+ URL location = node.getLocationURL();
if (unresolvables.get(location) != null)
// If it is already known unresolvable.
return null;
IContentType contentType = null;
contentType = resolvables.get(location);
- if (contentType != null)
+ if (contentType != null)
// If it is already known to have a certain content type.
return contentType;
// First check the content type by its name.
@@ -110,7 +105,7 @@ public class ContentTypeHelper {
/**
* Find the content type of the file using its content stream.
- *
+ *
* @param node
* The file node.
* @return The content type of the file.
@@ -119,13 +114,12 @@ public class ContentTypeHelper {
* @throws IOException
* If something goes wrong during the content type parsing.
*/
- private IContentType findContentTypeByStream(FSTreeNode node)
- throws CoreException, IOException {
+ private IContentType findContentTypeByStream(FSTreeNode node) throws CoreException, IOException {
InputStream is = null;
try {
- if (!CacheManager.getInstance().isCacheStale(node)) {
- // If the local cache file is update to date, then use the local
- // cache file.
+ File file = CacheManager.getInstance().getCacheFile(node);
+ if (file.exists()) {
+ // If the local cache file exits.
IPath path = CacheManager.getInstance().getCachePath(node);
IFileStore fileStore = EFS.getLocalFileSystem().getStore(path);
is = fileStore.openInputStream(EFS.NONE, null);
@@ -134,8 +128,7 @@ public class ContentTypeHelper {
URL url = node.getLocationURL();
is = url.openStream();
}
- return Platform.getContentTypeManager().findContentTypeFor(is,
- node.name);
+ return Platform.getContentTypeManager().findContentTypeFor(is, node.name);
} finally {
if (is != null) {
try {
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/FSTreeNodePropertyTester.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/FSTreeNodePropertyTester.java
index 0e23f0a1b..4e7ada41c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/FSTreeNodePropertyTester.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/FSTreeNodePropertyTester.java
@@ -12,14 +12,18 @@
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+import java.io.File;
+
import org.eclipse.core.expressions.PropertyTester;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
/**
* The property tester of an FSTreeNode. The properties include "isFile"
* if it is a file node, "isDirectory" if it is a directory, "isBinaryFile"
* if it is a binary file, "isReadable" if it is readable, "isWritable" if
- * it is writable and "isExecutable" if it is executable.
+ * it is writable, "isExecutable" if it is executable and "getCacheState" to
+ * get a node's state.
*/
public class FSTreeNodePropertyTester extends PropertyTester {
@@ -42,6 +46,12 @@ public class FSTreeNodePropertyTester extends PropertyTester {
return node.isWritable();
} else if (property.equals("isExecutable")){ //$NON-NLS-1$
return node.isExecutable();
+ } else if (property.equals("getCacheState")){ //$NON-NLS-1$
+ File file = CacheManager.getInstance().getCacheFile(node);
+ if(!file.exists())
+ return false;
+ CacheState state = StateManager.getInstance().getCacheState(node);
+ return state.name().equals(expectedValue);
}
return false;
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/MergeHandler.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/MergeHandler.java
new file mode 100644
index 000000000..08d3b5cb6
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/MergeHandler.java
@@ -0,0 +1,46 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import org.eclipse.compare.CompareUI;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.LocalTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.MergeEditorInput;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.RemoteTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The handler used to merge a file which is conflicting with its remote file.
+ */
+public class MergeHandler extends AbstractHandler {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
+ FSTreeNode node = (FSTreeNode) selection.getFirstElement();
+ LocalTypedElement local = new LocalTypedElement(node);
+ RemoteTypedElement remote = new RemoteTypedElement(node);
+ IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
+ MergeEditorInput input = new MergeEditorInput(local, remote, page);
+ CompareUI.openCompareDialog(input);
+ return null;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/OpenFileHandler.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/OpenFileHandler.java
index 00214c396..b92ee3f39 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/OpenFileHandler.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/OpenFileHandler.java
@@ -9,6 +9,9 @@
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+import java.io.File;
+
+import org.eclipse.compare.CompareUI;
import org.eclipse.core.commands.AbstractHandler;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
@@ -17,9 +20,15 @@ import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.runtime.IPath;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.LocalTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.MergeEditorInput;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.RemoteTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PartInitException;
@@ -36,13 +45,14 @@ public class OpenFileHandler extends AbstractHandler {
*/
@Override
public Object execute(ExecutionEvent event) throws ExecutionException {
- IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getActiveMenuSelectionChecked(event);
+ IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
final FSTreeNode node = (FSTreeNode) selection.getFirstElement();
IWorkbenchPage page = HandlerUtil.getActiveSite(event).getPage();
if (ContentTypeHelper.getInstance().isBinaryFile(node)) {
// If the file is a binary file.
Shell parent = HandlerUtil.getActiveShell(event);
- MessageDialog.openWarning(parent, Messages.OpenFileHandler_Warning, Messages.OpenFileHandler_OpeningBinaryNotSupported);
+ MessageDialog.openWarning(parent, Messages.OpenFileHandler_Warning,
+ Messages.OpenFileHandler_OpeningBinaryNotSupported);
} else {
// Open the file node.
openFile(node, page);
@@ -61,13 +71,63 @@ public class OpenFileHandler extends AbstractHandler {
* The workbench page in which the editor is opened.
*/
private void openFile(FSTreeNode node, IWorkbenchPage page) {
- if (CacheManager.getInstance().isCacheStale(node)) {
- // If the file node's local cache is already stale, download it.
- Shell parent = page.getWorkbenchWindow().getShell();
- boolean successful = CacheManager.getInstance().download(node, parent);
- if (successful) openEditor(page, node);
- } else {
+ File file = CacheManager.getInstance().getCacheFile(node);
+ if (!file.exists()) {
+ // If the file node's local cache does not exist yet, download it.
+ boolean successful = CacheManager.getInstance().download(node);
+ if (!successful) {
+ return;
+ }
+ }
+ if (!CacheManager.getInstance().isAutoSaving()) {
openEditor(page, node);
+ } else {
+ try {
+ StateManager.getInstance().refreshState(node);
+ } catch (TCFException e) {
+ Shell parent = page.getWorkbenchWindow().getShell();
+ MessageDialog.openError(parent, Messages.StateManager_RefreshFailureTitle, e.getLocalizedMessage());
+ return;
+ }
+ CacheState state = StateManager.getInstance().getCacheState(node);
+ switch (state) {
+ case consistent:
+ openEditor(page, node);
+ break;
+ case modified: {
+ // If the file node's local cache has been modified, upload it
+ // before open it.
+ boolean successful = CacheManager.getInstance().upload(node);
+ if (successful)
+ openEditor(page, node);
+ }
+ break;
+ case outdated: {
+ // If the file node's local cache does not exist yet, download
+ // it.
+ boolean successful = CacheManager.getInstance().download(node);
+ if (successful)
+ openEditor(page, node);
+ }
+ break;
+ case conflict: {
+ String title = Messages.OpenFileHandler_ConflictingTitle;
+ String message = NLS.bind(Messages.OpenFileHandler_ConflictingMessage, node.name);
+ Shell parent = page.getWorkbenchWindow().getShell();
+ MessageDialog msgDialog = new MessageDialog(parent, title, null, message, MessageDialog.QUESTION, new String[] { Messages.OpenFileHandler_Merge, Messages.OpenFileHandler_OpenAnyway,
+ Messages.OpenFileHandler_Cancel }, 0);
+ int index = msgDialog.open();
+ if (index == 0) {
+ LocalTypedElement local = new LocalTypedElement(node);
+ RemoteTypedElement remote = new RemoteTypedElement(node);
+ MergeEditorInput input = new MergeEditorInput(local, remote, page);
+ CompareUI.openCompareDialog(input);
+ } else if (index == 1) {
+ openEditor(page, node);
+ }
+ }
+ break;
+ }
}
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RefreshHandler.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RefreshHandler.java
new file mode 100644
index 000000000..bb7ec71f7
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RefreshHandler.java
@@ -0,0 +1,45 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The handler to refresh the state of a file.
+ */
+public class RefreshHandler extends AbstractHandler {
+
+ /* (non-Javadoc)
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
+ FSTreeNode node = (FSTreeNode) selection.getFirstElement();
+ try {
+ StateManager.getInstance().refreshState(node);
+ } catch (TCFException e) {
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MessageDialog.openError(parent, Messages.StateManager_RefreshFailureTitle, e.getLocalizedMessage());
+ }
+ return null;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RevertHandler.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RevertHandler.java
new file mode 100644
index 000000000..83e27c185
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/RevertHandler.java
@@ -0,0 +1,38 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The handler to revert the content of the file from the remote file.
+ * This handler is enabled only when the file is modified or conflicting.
+ */
+public class RevertHandler extends AbstractHandler {
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
+ FSTreeNode node = (FSTreeNode) selection.getFirstElement();
+ CacheManager.getInstance().download(node);
+ return null;
+ }
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/StateManager.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/StateManager.java
new file mode 100644
index 000000000..e43b4c7fd
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/StateManager.java
@@ -0,0 +1,259 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import java.io.File;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.services.IFileSystem;
+import org.eclipse.tm.tcf.services.IFileSystem.DoneSetStat;
+import org.eclipse.tm.tcf.services.IFileSystem.DoneStat;
+import org.eclipse.tm.tcf.services.IFileSystem.FileAttrs;
+import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFFileSystemException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.internal.url.Rendezvous;
+import org.eclipse.tm.te.tcf.filesystem.internal.url.TCFUtilities;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
+import org.eclipse.tm.te.tcf.filesystem.model.FSModel;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+
+/**
+ * This class provides several utility methods to get, update, commit
+ * or refresh a file node's state.
+ *
+ */
+public class StateManager {
+
+ // The singleton instance.
+ private static StateManager instance;
+
+ /**
+ * Get the singleton user manager.
+ *
+ * @return The singleton cache manager.
+ */
+ public static StateManager getInstance() {
+ if (instance == null) {
+ instance = new StateManager();
+ }
+ return instance;
+ }
+
+ /**
+ * Create a StateManager fInstance.
+ */
+ private StateManager() {
+ }
+
+ /**
+ * Update the state of the specified node.
+ *
+ * @param node The tree node whose state is going to be updated.
+ * @throws TCFException
+ */
+ public void updateState(FSTreeNode node) throws TCFException {
+ updateFileStat(node, true);
+ }
+
+ /**
+ * Refresh the state of the specified node.
+ *
+ * @param node The tree node whose state is going to be refreshed.
+ * @throws TCFException
+ */
+ public void refreshState(FSTreeNode node) throws TCFException {
+ updateFileStat(node, false);
+ }
+
+ /**
+ * Update the file's state of the specified tree node. Synchronize the time stamp of
+ * the file with the base time stamp and that of the remote file if sync is true.
+ *
+ * @param node The tree node whose file state is going to be updated.
+ * @param sync If its base time stamp and its remote file's time stamp should be synchronized.
+ */
+ private void updateFileStat(final FSTreeNode node, final boolean sync) throws TCFException {
+ IChannel channel = null;
+ try {
+ channel = TCFUtilities.openChannel(node.peerNode.getPeer());
+ if (channel != null) {
+ updateFileAttr(node, sync, channel);
+ }
+ } finally {
+ if (channel != null)
+ channel.close();
+ }
+ }
+
+ private void updateFileAttr(final FSTreeNode node, final boolean sync, IChannel channel) throws TCFFileSystemException {
+ IFileSystem service = channel.getRemoteService(IFileSystem.class);
+ if (service != null) {
+ final TCFFileSystemException[] errors = new TCFFileSystemException[1];
+ final Rendezvous rendezvous = new Rendezvous();
+ String path = node.getLocation(true);
+ service.stat(path, new DoneStat() {
+ @Override
+ public void doneStat(IToken token, FileSystemException error, FileAttrs attrs) {
+ if (error == null) {
+ updateNodeAttr(node, attrs, sync);
+ } else {
+ String message = NLS.bind(Messages.StateManager_CannotGetFileStatMessage, new Object[]{node.name, error});
+ errors[0] = new TCFFileSystemException(message, error);
+ }
+ rendezvous.arrive();
+ }
+ });
+ try {
+ rendezvous.waiting(5000L);
+ } catch (InterruptedException e) {
+ String message = NLS.bind(Messages.StateManager_CannotGetFileStateMessage2, new Object[]{node.name, e});
+ errors[0] = new TCFFileSystemException(message, e);
+ }
+ if (errors[0] != null) {
+ throw errors[0];
+ }
+ }else{
+ String message = NLS.bind(Messages.StateManager_TCFNotProvideFSMessage, node.peerNode.getPeer().getID());
+ throw new TCFFileSystemException(message);
+ }
+ }
+
+ /**
+ * Update the file attribute of the specified tree node with the specified value
+ * and synchronize its base timestamp and its remote file's timestamp if "sync" is true.
+ *
+ * @param node The tree node whose file attribute is to updated.
+ * @param attr The new file attribute.
+ * @param sync If the timestamps should be synchronized.
+ */
+ void updateNodeAttr(FSTreeNode node, FileAttrs attr, boolean sync){
+ node.attr = attr;
+ if (sync) {
+ File file = CacheManager.getInstance().getCacheFile(node);
+ assert file.exists();
+ file.setLastModified(attr.mtime);
+ CacheManager.getInstance().setBaseTimestamp(node.getLocationURL(), attr.mtime);
+ }
+ FSModel.getInstance().fireNodeStateChanged(node);
+ }
+
+ /**
+ * Commit the content of the local file to the target.
+ *
+ * @param node The tree node whose local file is going to committed.
+ * @throws TCFException
+ */
+ public void commitState(final FSTreeNode node) throws TCFException {
+ File file = CacheManager.getInstance().getCacheFile(node);
+ assert file.exists();
+ long mtime = file.lastModified();
+ // Create the new file attribute based on the file's last modified time.
+ final IFileSystem.FileAttrs attrs = new IFileSystem.FileAttrs(node.attr.flags, node.attr.size, node.attr.uid, node.attr.gid, node.attr.permissions, node.attr.atime, mtime,
+ node.attr.attributes);
+ IChannel channel = null;
+ try {
+ channel = TCFUtilities.openChannel(node.peerNode.getPeer());
+ if (channel != null) {
+ commitFileAttr(node, attrs, channel);
+ }
+ } finally {
+ if (channel != null)
+ channel.close();
+ }
+ }
+
+ private void commitFileAttr(final FSTreeNode node, final IFileSystem.FileAttrs attrs, IChannel channel) throws TCFFileSystemException {
+ IFileSystem service = channel.getRemoteService(IFileSystem.class);
+ if (service != null) {
+ final TCFFileSystemException[] errors = new TCFFileSystemException[1];
+ final Rendezvous rendezvous = new Rendezvous();
+ String path = node.getLocation(true);
+ service.setstat(path, attrs, new DoneSetStat() {
+ @Override
+ public void doneSetStat(IToken token, FileSystemException error) {
+ if (error == null) {
+ commitNodeAttr(node, attrs);
+ } else {
+ String message = NLS.bind(Messages.StateManager_CannotSetFileStateMessage, new Object[] { node.name, error });
+ errors[0] = new TCFFileSystemException(message, error);
+ }
+ rendezvous.arrive();
+ }
+ });
+ try {
+ rendezvous.waiting(5000L);
+ } catch (InterruptedException e) {
+ String message = NLS.bind(Messages.StateManager_CannotSetFileStateMessage2, new Object[] { node.name, e });
+ errors[0] = new TCFFileSystemException(message, e);
+ }
+ if (errors[0] != null) {
+ throw errors[0];
+ }
+ } else {
+ String message = NLS.bind(Messages.StateManager_TCFNotProvideFSMessage2, node.peerNode.getPeer().getID());
+ throw new TCFFileSystemException(message);
+ }
+ }
+
+ /**
+ * Commit the file attribute of the specified tree node with the specified value.
+ *
+ * @param node The tree node whose file attribute is to committed.
+ * @param attr The new file attribute.
+ */
+ void commitNodeAttr(FSTreeNode node, FileAttrs attr){
+ node.attr = attr;
+ CacheManager.getInstance().setBaseTimestamp(node.getLocationURL(), attr.mtime);
+ FSModel.getInstance().fireNodeStateChanged(node);
+ }
+
+ /**
+ * Get the local file's state of the specified tree node. The local file must exist
+ * before calling this method to get its state.
+ *
+ * @param node The tree node whose local file state is going to retrieved.
+ * @return The tree node's latest cache state.
+ */
+ public CacheState getCacheState(FSTreeNode node) {
+ File file = CacheManager.getInstance().getCacheFile(node);
+ if(!file.exists())
+ return CacheState.consistent;
+ long ltime = file.lastModified();
+ long btime = CacheManager.getInstance().getBaseTimestamp(node.getLocationURL());
+ long mtime = 0;
+ if(node.attr!=null)
+ mtime = node.attr.mtime;
+ if(btime == ltime){
+ if(isUnchanged(mtime, btime))
+ return CacheState.consistent;
+ return CacheState.outdated;
+ }
+ if(isUnchanged(mtime, btime))
+ return CacheState.modified;
+ return CacheState.conflict;
+ }
+
+ /**
+ * Compare the modified time of the remote file and the base timestamp
+ * and see if they are equal to each other.
+ *
+ * @param mtime The modified time of the remote file.
+ * @param btime The base timestamp cached.
+ * @return true if they are equal in second precision.
+ */
+ private boolean isUnchanged(long mtime, long btime){
+ return Math.abs(mtime-btime)/1000 == 0;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UpdateHandler.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UpdateHandler.java
new file mode 100644
index 000000000..56f367a19
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UpdateHandler.java
@@ -0,0 +1,89 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import java.io.File;
+
+import org.eclipse.compare.CompareUI;
+import org.eclipse.core.commands.AbstractHandler;
+import org.eclipse.core.commands.ExecutionEvent;
+import org.eclipse.core.commands.ExecutionException;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.LocalTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.MergeEditorInput;
+import org.eclipse.tm.te.tcf.filesystem.internal.compare.RemoteTypedElement;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.CacheState;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.handlers.HandlerUtil;
+
+/**
+ * The handler to update the local file's content with the latest of its remote file.
+ *
+ */
+public class UpdateHandler extends AbstractHandler {
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent)
+ */
+ @Override
+ public Object execute(ExecutionEvent event) throws ExecutionException {
+ IStructuredSelection selection = (IStructuredSelection) HandlerUtil.getCurrentSelectionChecked(event);
+ FSTreeNode node = (FSTreeNode) selection.getFirstElement();
+ try {
+ StateManager.getInstance().refreshState(node);
+ } catch (TCFException e) {
+ Shell parent = HandlerUtil.getActiveShell(event);
+ MessageDialog.openError(parent, Messages.StateManager_RefreshFailureTitle, e.getLocalizedMessage());
+ return null;
+ }
+ Shell parent = HandlerUtil.getActiveShell(event);
+ File file = CacheManager.getInstance().getCacheFile(node);
+ if(file.exists()){
+ CacheState state = StateManager.getInstance().getCacheState(node);
+ switch (state) {
+ case conflict:
+ String title = Messages.UpdateHandler_StateChangedDialogTitle;
+ String message = NLS.bind(Messages.UpdateHandler_StateChangedMessage, node.name);
+ MessageDialog msgDialog = new MessageDialog(parent, title, null, message,
+ MessageDialog.QUESTION, new String[]{Messages.UpdateHandler_Merge,
+ Messages.UpdateHandler_UpdateAnyway, Messages.UpdateHandler_Cancel}, 0);
+ int index = msgDialog.open();
+ if (index == 0) {
+ LocalTypedElement local = new LocalTypedElement(node);
+ RemoteTypedElement remote = new RemoteTypedElement(node);
+ IWorkbenchPage page = HandlerUtil.getActiveSite(event).getPage();
+ MergeEditorInput input = new MergeEditorInput(local, remote, page);
+ CompareUI.openCompareDialog(input);
+ }else if(index == 1){
+ CacheManager.getInstance().download(node);
+ }
+ break;
+ case modified:
+ break;
+ case consistent:
+ break;
+ case outdated:
+ CacheManager.getInstance().download(node);
+ break;
+ }
+ }else{
+ CacheManager.getInstance().download(node);
+ }
+ return null;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UserManager.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UserManager.java
new file mode 100644
index 000000000..826f1b20a
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/handlers/UserManager.java
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.handlers;
+
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.services.IFileSystem;
+import org.eclipse.tm.tcf.services.IFileSystem.DoneUser;
+import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
+import org.eclipse.tm.te.tcf.filesystem.internal.UserAccount;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFException;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFFileSystemException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.internal.url.Rendezvous;
+import org.eclipse.tm.te.tcf.filesystem.internal.url.TCFUtilities;
+import org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModel;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * A facility class to retrieve the user's information for a target file system.
+ */
+public class UserManager {
+ // The key to save and retrieve the user account in a peer model.
+ private static final String USER_ACCOUNT_KEY = "user.account"; //$NON-NLS-1$
+
+ // The singleton fInstance.
+ private static UserManager instance;
+
+ /**
+ * Get the singleton user manager.
+ *
+ * @return The singleton cache manager.
+ */
+ public static UserManager getInstance() {
+ if (instance == null) {
+ instance = new UserManager();
+ }
+ return instance;
+ }
+
+ private UserManager() {
+ }
+
+ /**
+ * Get the user account from the peer using the channel connected to the
+ * remote target.
+ *
+ * @param channel
+ * The channel connected to the remote target.
+ * @return The user account information or null if it fails.
+ */
+ private UserAccount getUserByChannel(final IChannel channel) throws TCFFileSystemException {
+ IFileSystem service = channel.getRemoteService(IFileSystem.class);
+ if (service != null) {
+ final TCFFileSystemException[] errors = new TCFFileSystemException[1];
+ final Rendezvous rendezvous = new Rendezvous();
+ final UserAccount[] accounts = new UserAccount[1];
+ service.user(new DoneUser() {
+ @Override
+ public void doneUser(IToken token, FileSystemException error, int real_uid, int effective_uid, int real_gid, int effective_gid, String home) {
+ if (error == null) {
+ accounts[0] = new UserAccount(real_uid, real_gid, effective_uid, effective_gid, home);
+ }else {
+ String message = NLS.bind(Messages.UserManager_CannotGetUserAccountMessage, channel.getRemotePeer().getID());
+ errors[0] = new TCFFileSystemException(message, error);
+ }
+ rendezvous.arrive();
+ }
+ });
+ try {
+ rendezvous.waiting(5000L);
+ } catch (InterruptedException e) {
+ String message = NLS.bind(Messages.UserManager_CannotGetUserAccountMessage2, channel.getRemotePeer().getID());
+ errors[0] = new TCFFileSystemException(message, e);
+ }
+ if (errors[0] != null) {
+ throw errors[0];
+ }
+ return accounts[0];
+ }
+ String message = NLS.bind(Messages.UserManager_TCFNotProvideFSMessage, channel.getRemotePeer().getID());
+ throw new TCFFileSystemException(message);
+ }
+
+ /**
+ * Get the information of the client user account.
+ *
+ * @return The client user account's information.
+ */
+ public UserAccount getUserAccount(IPeerModel peerNode) {
+ UserAccount account = getUserFromPeer(peerNode);
+ if (account == null) {
+ IChannel channel = null;
+ try{
+ channel = TCFUtilities.openChannel(peerNode.getPeer());
+ if (channel != null) {
+ account = getUserByChannel(channel);
+ if (account != null)
+ setUserToPeer(peerNode, account);
+ }
+ }catch(TCFException e){
+ Shell parent = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MessageDialog.openError(parent, Messages.UserManager_UserAccountTitle, e.getLocalizedMessage());
+ }finally{
+ if(channel!=null){
+ channel.close();
+ }
+ }
+ }
+ return account;
+ }
+
+ /**
+ * Get the user account stored in the specified peer model using a key named
+ * "user.account" defined by the constant USER_ACCOUNT_KEY.
+ *
+ * @param peer
+ * The peer model from which the user account is retrieved.
+ * @return The user account if it exists or null if not.
+ */
+ private UserAccount getUserFromPeer(final IPeerModel peer) {
+ if (Protocol.isDispatchThread()) {
+ return (UserAccount) peer.getProperty(USER_ACCOUNT_KEY);
+ }
+ final UserAccount[] accounts = new UserAccount[1];
+ Protocol.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ accounts[0] = (UserAccount) peer.getProperty(USER_ACCOUNT_KEY);
+ }
+ });
+ return accounts[0];
+ }
+
+ /**
+ * Save the user account to the specified peer model using a key named
+ * "user.account" defined by the constant USER_ACCOUNT_KEY.
+ *
+ * @param peer
+ * The peer model to which the user account is saved.
+ */
+ private void setUserToPeer(final IPeerModel peer, final UserAccount account) {
+ assert peer != null && account != null;
+ if (Protocol.isDispatchThread()) {
+ peer.setProperty(USER_ACCOUNT_KEY, account);
+ } else {
+ Protocol.invokeAndWait(new Runnable() {
+ @Override
+ public void run() {
+ peer.setProperty(USER_ACCOUNT_KEY, account);
+ }
+ });
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.java
index c6ba5634a..787822b58 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.java
@@ -103,6 +103,16 @@ public class Messages extends NLS {
public static String CacheManager_DownloadingProgress;
public static String CacheManager_KBs;
public static String CacheManager_MBs;
+ public static String CacheManager_UploadingProgress;
+ public static String CacheManager_UploadNFiles;
+ public static String CacheManager_UploadSingleFile;
+ public static String CmmitHandler_Cancel;
+ public static String CmmitHandler_CommitAnyway;
+ public static String CmmitHandler_ErrorTitle;
+ public static String CmmitHandler_FileDeleted;
+ public static String CmmitHandler_Merge;
+ public static String CmmitHandler_StateChangedDialogTitle;
+ public static String CmmitHandler_StateChangedMessage;
public static String InformationPage_Accessed;
public static String InformationPage_Advanced;
public static String InformationPage_Attributes;
@@ -124,7 +134,13 @@ public class Messages extends NLS {
public static String FSTreeControl_column_modified_label;
public static String FSOpenFileDialog_title;
+ public static String LocalTypedElement_SavingFile;
+ public static String OpenFileHandler_Cancel;
+ public static String OpenFileHandler_ConflictingMessage;
+ public static String OpenFileHandler_ConflictingTitle;
+ public static String OpenFileHandler_Merge;
+ public static String OpenFileHandler_OpenAnyway;
public static String OpenFileHandler_OpeningBinaryNotSupported;
public static String OpenFileHandler_Warning;
public static String PermissionsGroup_Executable;
@@ -133,6 +149,26 @@ public class Messages extends NLS {
public static String PermissionsGroup_Readable;
public static String PermissionsGroup_UserPermissions;
public static String PermissionsGroup_Writable;
+ public static String RemoteTypedElement_GettingRemoteContent;
+ public static String SaveAllListener_Cancel;
+ public static String SaveAllListener_Merge;
+ public static String SaveAllListener_SaveAnyway;
+ public static String SaveAllListener_SingularMessage;
+ public static String SaveAllListener_StateChangedDialogTitle;
+ public static String SaveListener_Cancel;
+ public static String SaveListener_Merge;
+ public static String SaveListener_SaveAnyway;
+ public static String SaveListener_StateChangedDialogTitle;
+ public static String SaveListener_StateChangedMessage;
+ public static String StateManager_CannotGetFileStateMessage2;
+ public static String StateManager_CannotGetFileStatMessage;
+ public static String StateManager_CannotSetFileStateMessage;
+ public static String StateManager_CannotSetFileStateMessage2;
+ public static String StateManager_CommitFailureTitle;
+ public static String StateManager_RefreshFailureTitle;
+ public static String StateManager_TCFNotProvideFSMessage;
+ public static String StateManager_TCFNotProvideFSMessage2;
+ public static String StateManager_UpdateFailureTitle;
public static String TcfInputStream_CloseTimeout;
public static String TcfInputStream_NoDataAvailable;
public static String TcfInputStream_NoFileReturned;
@@ -141,4 +177,23 @@ public class Messages extends NLS {
public static String TcfInputStream_OpenTCFTimeout;
public static String TcfInputStream_ReadTimeout;
public static String TcfInputStream_StreamClosed;
+ public static String TcfOutputStream_StreamClosed;
+ public static String TcfOutputStream_WriteTimeout;
+ public static String TcfURLConnection_CloseFileTimeout;
+ public static String TcfURLConnection_NoFileHandleReturned;
+ public static String TcfURLConnection_NoFSServiceAvailable;
+ public static String TcfURLConnection_NoSuchTcfAgent;
+ public static String TcfURLConnection_OpenFileTimeout;
+ public static String TcfURLConnection_OpenTCFChannelTimeout;
+ public static String TCFUtilities_OpeningFailureMessage;
+ public static String TCFUtilities_OpeningFailureTitle;
+ public static String UpdateHandler_Cancel;
+ public static String UpdateHandler_Merge;
+ public static String UpdateHandler_StateChangedDialogTitle;
+ public static String UpdateHandler_StateChangedMessage;
+ public static String UpdateHandler_UpdateAnyway;
+ public static String UserManager_CannotGetUserAccountMessage;
+ public static String UserManager_CannotGetUserAccountMessage2;
+ public static String UserManager_TCFNotProvideFSMessage;
+ public static String UserManager_UserAccountTitle;
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.properties
index b5d362d6c..08e539479 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.properties
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/nls/Messages.properties
@@ -57,6 +57,22 @@ CacheManager_DownloadingError=Downloading Error
CacheManager_DownloadingProgress=Downloading {0}/{1}.
CacheManager_KBs=\ KBs
CacheManager_MBs=\ MBs
+CacheManager_UploadingProgress=Uploading file {0}: {1}/{2}
+CacheManager_UploadNFiles=Uploading {0} files...
+CacheManager_UploadSingleFile=Uploading file {0}...
+CmmitHandler_Cancel=Cancel
+CmmitHandler_CommitAnyway=Commit anyway
+CmmitHandler_ErrorTitle=File Deleted
+CmmitHandler_FileDeleted=The local file {0} that you are trying to commit has been deleted\!
+CmmitHandler_Merge=Merge
+CmmitHandler_StateChangedDialogTitle=State Changed
+CmmitHandler_StateChangedMessage={0} on the target has changed and is conflicting with the local file. What do you want?
+LocalTypedElement_SavingFile=Saving file:
+OpenFileHandler_Cancel=Cancel
+OpenFileHandler_ConflictingMessage=The local {0} is conflicting with the remote version. What do you want?
+OpenFileHandler_ConflictingTitle=Conflicting content
+OpenFileHandler_Merge=Merge
+OpenFileHandler_OpenAnyway=Open anyway
OpenFileHandler_OpeningBinaryNotSupported=Opening a binary file is not supported yet.
OpenFileHandler_Warning=Warning
@@ -66,6 +82,26 @@ PermissionsGroup_OtherPermissions=Other:
PermissionsGroup_Readable=Readable
PermissionsGroup_UserPermissions=User:
PermissionsGroup_Writable=Writable
+RemoteTypedElement_GettingRemoteContent=Getting content from the remote file:
+SaveAllListener_Cancel=Cancel
+SaveAllListener_Merge=Merge
+SaveAllListener_SaveAnyway=Save anyway
+SaveAllListener_SingularMessage=The file {0} on the target has changed and is conflicting with the local file. What do you want?
+SaveAllListener_StateChangedDialogTitle=State Changed
+SaveListener_Cancel=Cancel
+SaveListener_Merge=Merge
+SaveListener_SaveAnyway=Save anyway
+SaveListener_StateChangedDialogTitle=State Changed
+SaveListener_StateChangedMessage={0} on the target has changed and is conflicting with the local file. What do you want?
+StateManager_CannotGetFileStateMessage2=Cannot get the file's stat of {0}\!. Caused by {1}
+StateManager_CannotGetFileStatMessage=Cannot get the file's stat of {0}\!. Caused by {1}
+StateManager_CannotSetFileStateMessage=Cannot set the file's stat of {0}\!. Caused by {1}
+StateManager_CannotSetFileStateMessage2=Cannot set the file's stat of {0}\!. Caused by {1}
+StateManager_CommitFailureTitle=Commit Failure
+StateManager_RefreshFailureTitle=Refresh Failure
+StateManager_TCFNotProvideFSMessage=This TCF agent, {0}, does not provide a file system service\!
+StateManager_TCFNotProvideFSMessage2=This TCF agent, {0}, does not provide a file system service\!
+StateManager_UpdateFailureTitle=Update Failure
TcfInputStream_CloseTimeout=Closing has timed out\!
TcfInputStream_NoDataAvailable=No data available
TcfInputStream_NoFileReturned=No file handle returned\!
@@ -74,3 +110,22 @@ TcfInputStream_OpenFileTimeout=Opening file has timed out\!
TcfInputStream_OpenTCFTimeout=Opening TCF channel has timed out\!
TcfInputStream_ReadTimeout=Reading has timed out\!
TcfInputStream_StreamClosed=Stream is already closed\!
+TcfOutputStream_StreamClosed=Stream is already closed\!
+TcfOutputStream_WriteTimeout=Writing has timed out\!
+TcfURLConnection_CloseFileTimeout=Closing has timed out\!
+TcfURLConnection_NoFileHandleReturned=No file handle returned\!
+TcfURLConnection_NoFSServiceAvailable=No remote File System Service available\!
+TcfURLConnection_NoSuchTcfAgent=TCF agent is already disconnected\!
+TcfURLConnection_OpenFileTimeout=Opening file has timed out\!
+TcfURLConnection_OpenTCFChannelTimeout=Opening TCF channel has timed out\!
+TCFUtilities_OpeningFailureMessage=We cannot open a TCF channel to the target: {0}. It is caused by {1}.
+TCFUtilities_OpeningFailureTitle=Opening Channel
+UpdateHandler_Cancel=Cancel
+UpdateHandler_Merge=Merge
+UpdateHandler_StateChangedDialogTitle=State Changed
+UpdateHandler_StateChangedMessage=The local {0} has changed and is conflicting with the remote file. What do you want?
+UpdateHandler_UpdateAnyway=Update anyway
+UserManager_CannotGetUserAccountMessage=Cannot get the user account from the agent {0}
+UserManager_CannotGetUserAccountMessage2=Cannot get the user account from the agent {0}. Caused by: networking too slow.
+UserManager_TCFNotProvideFSMessage=This TCF agent, {0}, does not provide a file system service\!
+UserManager_UserAccountTitle=User Account
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/PreferencesInitializer.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/PreferencesInitializer.java
index c8e247ca0..134750f39 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/PreferencesInitializer.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/PreferencesInitializer.java
@@ -12,6 +12,7 @@ package org.eclipse.tm.te.tcf.filesystem.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.jface.preference.IPreferenceStore;
import org.eclipse.tm.te.tcf.filesystem.activator.UIPlugin;
import org.eclipse.tm.te.tcf.filesystem.interfaces.preferences.IPreferenceKeys;
@@ -39,5 +40,7 @@ public class PreferencesInitializer extends AbstractPreferenceInitializer {
// [Hidden] Editor content contribution: default on
prefs.putBoolean(IPreferenceKeys.PREF_FEATURE_ENABLE_EDITOR_CONTENT_CONTRIBUTION, true);
}
+ IPreferenceStore preferenceStore = UIPlugin.getDefault().getPreferenceStore();
+ preferenceStore.setDefault(TargetExplorerPreferencePage.PREF_AUTOSAVING, TargetExplorerPreferencePage.DEFAULT_AUTOSAVING);
}
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/TargetExplorerPreferencePage.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/TargetExplorerPreferencePage.java
new file mode 100644
index 000000000..a00d965f3
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/preferences/TargetExplorerPreferencePage.java
@@ -0,0 +1,61 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.preferences;
+
+import org.eclipse.jface.preference.BooleanFieldEditor;
+import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.tm.te.tcf.filesystem.activator.UIPlugin;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPreferencePage;
+
+/**
+ * The preference page for configuring the preference options for Target
+ * Explorer File System Explorer.
+ *
+ */
+public class TargetExplorerPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage {
+ // The preference key to access the option of auto saving
+ public static final String PREF_AUTOSAVING = "PrefAutoSaving"; //$NON-NLS-1$
+ // The default value of the option of auto saving.
+ public static final boolean DEFAULT_AUTOSAVING = true;
+
+ // The editor to edit the value of auto saving.
+ protected BooleanFieldEditor fAutoSaving;
+
+ /***
+ * Create a preference page for Target Explorer File System Explorer.
+ */
+ public TargetExplorerPreferencePage() {
+ super(GRID);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.preference.FieldEditorPreferencePage#createFieldEditors()
+ */
+ @Override
+ protected void createFieldEditors() {
+ UIPlugin plugin = UIPlugin.getDefault();
+ IPreferenceStore preferenceStore = plugin.getPreferenceStore();
+ setPreferenceStore(preferenceStore);
+ fAutoSaving = new BooleanFieldEditor(PREF_AUTOSAVING, "Automatically upload files to targets upon saving.", //$NON-NLS-1$
+ getFieldEditorParent());
+ addField(fAutoSaving);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench)
+ */
+ @Override
+ public void init(IWorkbench workbench) {
+ // do nothing
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TCFUtilities.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TCFUtilities.java
new file mode 100644
index 000000000..b27f3ed02
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TCFUtilities.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.url;
+
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tm.tcf.protocol.IChannel;
+import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
+import org.eclipse.tm.tcf.protocol.IPeer;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFChannelException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+
+/**
+ * A utilities class that provides common TCF operations.
+ */
+public class TCFUtilities {
+
+ /**
+ * Open a channel connected to the target represented by the peer.
+ *
+ * @return The channel or null if the operation fails.
+ */
+ public static IChannel openChannel(final IPeer peer) throws TCFChannelException {
+ final Rendezvous rendezvous = new Rendezvous();
+ final TCFChannelException[] errors = new TCFChannelException[1];
+ final IChannel[] channels = new IChannel[1];
+ channels[0] = peer.openChannel();
+ channels[0].addChannelListener(new IChannelListener() {
+ @Override
+ public void onChannelOpened() {
+ rendezvous.arrive();
+ }
+
+ @Override
+ public void onChannelClosed(Throwable error) {
+ if (error != null) {
+ String message = NLS.bind(Messages.TCFUtilities_OpeningFailureMessage,
+ new Object[]{peer.getID(), error.getLocalizedMessage()});
+ errors[0] = new TCFChannelException(message, error);
+ rendezvous.arrive();
+ }
+ }
+
+ @Override
+ public void congestionLevel(int level) {
+ }
+ });
+ try {
+ rendezvous.waiting(5000L);
+ } catch (InterruptedException e) {
+ String message = NLS.bind(Messages.TCFUtilities_OpeningFailureMessage,
+ new Object[]{peer.getID(), e.getLocalizedMessage()});
+ errors[0] = new TCFChannelException(message, e);
+ }
+ if(errors[0] != null){
+ throw errors[0];
+ }
+ return channels[0];
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfInputStream.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfInputStream.java
index f446ef585..6e41bb15f 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfInputStream.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfInputStream.java
@@ -12,18 +12,10 @@ package org.eclipse.tm.te.tcf.filesystem.internal.url;
import java.io.IOException;
import java.io.InputStream;
-import org.eclipse.core.runtime.Assert;
-import org.eclipse.tm.tcf.protocol.IChannel;
-import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
-import org.eclipse.tm.tcf.protocol.IPeer;
import org.eclipse.tm.tcf.protocol.IToken;
-import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IFileSystem;
-import org.eclipse.tm.tcf.services.IFileSystem.DoneClose;
-import org.eclipse.tm.tcf.services.IFileSystem.DoneOpen;
import org.eclipse.tm.tcf.services.IFileSystem.DoneRead;
import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
-import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle;
import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
/**
@@ -34,21 +26,6 @@ public class TcfInputStream extends InputStream {
// Default chunk size while pumping the data.
private static final int DEFAULT_CHUNK_SIZE = 5 * 1024;
- // If the stream has already connected.
- private boolean connected;
-
- // The TCF agent peer.
- IPeer peer;
- // The remote path to the resource.
- String path;
-
- // The TCF channel used to open and read the resource.
- IChannel channel;
- // The file system service used to open and read the resource.
- IFileSystem service;
- // The file's handle
- IFileHandle handle;
-
// Current reading position
long position;
// The byte array used to buffer data.
@@ -66,14 +43,11 @@ public class TcfInputStream extends InputStream {
// The chunk size of the reading buffer.
int chunk_size = 0;
- // Channel opening timeout.
- long connectTimeout;
- // File opening timeout.
- long openTimeout;
// File reading timeout.
- long readTimeout;
- // File closing timeout.
- long closeTimeout;
+ int timeout;
+
+ // The URL Connection
+ TcfURLConnection connection;
/**
* Create a TCF input stream connected the specified peer with specified
@@ -84,8 +58,8 @@ public class TcfInputStream extends InputStream {
* @param path
* The path to the remote resource.
*/
- public TcfInputStream(IPeer peer, String path) {
- this(peer, path, DEFAULT_CHUNK_SIZE);
+ public TcfInputStream(TcfURLConnection connection) {
+ this(connection, DEFAULT_CHUNK_SIZE);
}
/**
@@ -99,112 +73,18 @@ public class TcfInputStream extends InputStream {
* @param chunk_size
* The buffer size.
*/
- public TcfInputStream(IPeer peer, final String path, int chunk_size) {
- this.peer = peer;
- this.path = path;
+ public TcfInputStream(TcfURLConnection connection, int chunk_size) {
+ this.connection = connection;
this.chunk_size = chunk_size;
}
/**
- * Set the timeout for opening a TCF channel.
- *
- * @param connectTimeout the timeout in milliseconds.
- */
- void setConnectTimeout(long channelTimeout) {
- this.connectTimeout = channelTimeout;
- }
-
- /**
- * Set the timeout for opening a file.
- *
- * @param openTimeout the timeout in milliseconds.
- */
- void setOpenTimeout(long openTimeout) {
- this.openTimeout = openTimeout;
- }
-
- /**
* Set the timeout for reading a file.
*
- * @param readTimeout the timeout in milliseconds.
- */
- void setReadTimeout(long readTimeout) {
- this.readTimeout = readTimeout;
- }
-
- /**
- * Set the timeout for closing a file.
- *
- * @param closeTimeout the timeout in milliseconds.
+ * @param timeout the timeout in milliseconds.
*/
- void setCloseTimeout(long closeTimeout) {
- this.closeTimeout = closeTimeout;
- }
-
-
- /**
- * Open and connect the input stream to the agent peer.
- *
- * @throws IOException
- * Thrown when the connecting is failed.
- */
- private void connect() throws IOException {
- final Rendezvous rendezvous = new Rendezvous();
- // Open the channel
- channel = peer.openChannel();
- channel.addChannelListener(new IChannelListener() {
- @Override
- public void onChannelOpened() {
- Assert.isTrue(Protocol.isDispatchThread());
- service = channel.getRemoteService(IFileSystem.class);
- rendezvous.arrive();
- }
-
- @Override
- public void onChannelClosed(Throwable error) {
- }
-
- @Override
- public void congestionLevel(int level) {
- }
- });
- // Wait for the end of the opening.
- try {
- rendezvous.waiting(connectTimeout);
- } catch (InterruptedException e) {
- throw new IOException(Messages.TcfInputStream_OpenTCFTimeout);
- }
- if (service != null) {
- rendezvous.reset();
- final FileSystemException[] errors = new FileSystemException[1];
- // Open the file.
- service.open(path, IFileSystem.TCF_O_READ, null, new DoneOpen() {
- @Override
- public void doneOpen(IToken token, FileSystemException error,
- IFileHandle hdl) {
- errors[0] = error;
- handle = hdl;
- // Rendezvous
- rendezvous.arrive();
- }
- });
- try {
- rendezvous.waiting(openTimeout);
- } catch (InterruptedException e) {
- throw new IOException(Messages.TcfInputStream_OpenFileTimeout);
- }
- if (errors[0] != null) {
- IOException exception = new IOException(errors[0].toString());
- exception.initCause(errors[0]);
- throw exception;
- }
- if (handle == null) {
- throw new IOException(Messages.TcfInputStream_NoFileReturned);
- }
- } else {
- throw new IOException(Messages.TcfInputStream_NoFSServiceAvailable);
- }
- connected = true;
+ void setTimeout(int readTimeout) {
+ this.timeout = readTimeout;
}
/*
@@ -214,9 +94,6 @@ public class TcfInputStream extends InputStream {
*/
@Override
public int read() throws IOException {
- if (!connected) {
- connect();
- }
if (closed)
throw new IOException(Messages.TcfInputStream_StreamClosed);
if (ERROR != null) {
@@ -253,10 +130,10 @@ public class TcfInputStream extends InputStream {
*/
private void readBlock() {
final Rendezvous rendezvous = new Rendezvous();
- service.read(handle, position, chunk_size, new DoneRead() {
+ IFileSystem service = connection.handle.getService();
+ service.read(connection.handle, position, chunk_size, new DoneRead() {
@Override
- public void doneRead(IToken token, FileSystemException error,
- byte[] data, boolean eof) {
+ public void doneRead(IToken token, FileSystemException error, byte[] data, boolean eof) {
if (error != null) {
ERROR = error;
}
@@ -274,7 +151,7 @@ public class TcfInputStream extends InputStream {
});
// Waiting for reading.
try {
- rendezvous.waiting(readTimeout);
+ rendezvous.waiting(timeout);
} catch (InterruptedException e) {
ERROR = new IOException(Messages.TcfInputStream_ReadTimeout);
}
@@ -287,21 +164,8 @@ public class TcfInputStream extends InputStream {
*/
@Override
public void close() throws IOException {
- if (connected && !closed) {
- final Rendezvous rendezvous = new Rendezvous();
- service.close(handle, new DoneClose() {
- @Override
- public void doneClose(IToken token, FileSystemException error) {
- rendezvous.arrive();
- }
- });
- try {
- rendezvous.waiting(closeTimeout);
- } catch (InterruptedException e) {
- throw new IOException(Messages.TcfInputStream_CloseTimeout);
- }
- channel.close();
- super.close();
+ if (!closed) {
+ connection.closeStream(this);
closed = true;
}
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfOutputStream.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfOutputStream.java
new file mode 100644
index 000000000..b0175744e
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfOutputStream.java
@@ -0,0 +1,146 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * William Chen (Wind River) - [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.internal.url;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.services.IFileSystem;
+import org.eclipse.tm.tcf.services.IFileSystem.DoneWrite;
+import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+
+/**
+ * The TCF output stream returned by {@link TcfURLConnection#getOutputStream()}.
+ *
+ */
+public class TcfOutputStream extends OutputStream {
+ // Default chunk size while pumping the data.
+ private static final int DEFAULT_CHUNK_SIZE = 5 * 1024;
+
+ // Current writing position
+ long position;
+ // The byte array used to buffer data.
+ byte[] buffer;
+ // The offset being written in the buffer.
+ int offset;
+
+ // If the stream has been closed.
+ boolean closed;
+ // The current error during writing.
+ Exception ERROR;
+
+ // The chunk size of the writing buffer.
+ int chunk_size = 0;
+
+ // The URL Connection
+ TcfURLConnection connection;
+
+ // The timeout for writing data.
+ int timeout;
+ /**
+ * Create a TCF output stream connected the specified peer with specified
+ * path to the remote resource.
+ *
+ * @param peer
+ * The TCF agent peer.
+ * @param path
+ * The path to the remote resource.
+ */
+ public TcfOutputStream(TcfURLConnection connection) {
+ this(connection, DEFAULT_CHUNK_SIZE);
+ }
+
+ /**
+ * Create a TCF output stream connected the specified peer with specified
+ * path to the remote resource using the specified buffer size.
+ *
+ * @param peer
+ * The TCF agent peer.
+ * @param path
+ * The path to the remote resource.
+ * @param chunk_size
+ * The buffer size.
+ */
+ public TcfOutputStream(TcfURLConnection connection, int chunk_size) {
+ this.connection = connection;
+ this.chunk_size = chunk_size;
+ buffer = new byte[chunk_size];
+ offset = 0;
+ }
+
+ /**
+ * Set the timeout for writing a file.
+ *
+ * @param timeout The timeout for writing a file.
+ */
+ void setTimeout(int timeout){
+ this.timeout = timeout;
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#write(int)
+ */
+ @Override
+ public void write(int b) throws IOException {
+ if (closed)
+ throw new IOException(Messages.TcfOutputStream_StreamClosed);
+ if (ERROR != null) {
+ IOException exception = new IOException(ERROR.toString());
+ exception.initCause(ERROR);
+ throw exception;
+ }
+ if (offset < buffer.length) {
+ buffer[offset++] = (byte) b;
+ }
+ if (offset == buffer.length)
+ flush();
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#flush()
+ */
+ @Override
+ public void flush() throws IOException {
+ if (offset > 0) {
+ final Rendezvous rendezvous = new Rendezvous();
+ IFileSystem service = connection.handle.getService();
+ service.write(connection.handle, position, buffer, 0, offset, new DoneWrite() {
+ @Override
+ public void doneWrite(IToken token, FileSystemException error) {
+ if (error != null) {
+ ERROR = error;
+ }
+ position += offset;
+ offset = 0;
+ rendezvous.arrive();
+ }
+ });
+ // Waiting for writing.
+ try {
+ rendezvous.waiting(timeout);
+ } catch (InterruptedException e) {
+ ERROR = new IOException(Messages.TcfOutputStream_WriteTimeout);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see java.io.OutputStream#close()
+ */
+ @Override
+ public void close() throws IOException {
+ if (!closed) {
+ connection.closeStream(this);
+ closed = true;
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfURLConnection.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfURLConnection.java
index 7cf06beda..7b24e513f 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfURLConnection.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/internal/url/TcfURLConnection.java
@@ -9,16 +9,29 @@
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.internal.url;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
+import java.io.OutputStream;
import java.net.URL;
import java.net.URLConnection;
+import org.eclipse.tm.tcf.protocol.IChannel;
import org.eclipse.tm.tcf.protocol.IPeer;
-import org.eclipse.tm.tcf.protocol.Protocol;
+import org.eclipse.tm.tcf.protocol.IToken;
+import org.eclipse.tm.tcf.services.IFileSystem;
+import org.eclipse.tm.tcf.services.IFileSystem.DoneClose;
+import org.eclipse.tm.tcf.services.IFileSystem.DoneOpen;
+import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
+import org.eclipse.tm.tcf.services.IFileSystem.IFileHandle;
+import org.eclipse.tm.te.tcf.filesystem.internal.exceptions.TCFChannelException;
+import org.eclipse.tm.te.tcf.filesystem.internal.nls.Messages;
+import org.eclipse.tm.te.tcf.filesystem.model.FSModel;
+import org.eclipse.tm.te.tcf.filesystem.model.FSTreeNode;
+
/**
- * The URL connection returned by TCF url stream service used to handle
- * "tcf" stream protocol.
+ * The URL connection returned by TCF stream service used to handler "tcf"
+ * stream protocol.
*/
public class TcfURLConnection extends URLConnection {
// Default connecting timeout.
@@ -27,29 +40,38 @@ public class TcfURLConnection extends URLConnection {
private static final int DEFAULT_OPEN_TIMEOUT = 5000;
// Default file reading timeout.
private static final int DEFAULT_READ_TIMEOUT = 5000;
- //Default file closing timeout.
+ // Default file closing timeout.
private static final int DEFAULT_CLOSE_TIMEOUT = 5000;
// The schema name of the stream protocol.
public static final String PROTOCOL_SCHEMA = "tcf"; //$NON-NLS-1$
+
// The input stream of this connection.
private TcfInputStream inputStream;
+ // The output stream of this connection.
+ private TcfOutputStream outputStream;
+
// The TCF agent peer of the connection.
private IPeer peer;
// The path to the resource on the remote file system.
private String path;
// The timeout for opening a file.
- private long openTimeout;
+ private int openTimeout;
// The timeout for closing a file.
- private long closeTimeout;
+ private int closeTimeout;
+
+ // The TCF channel used to open and read the resource.
+ IChannel channel;
+ // The file's handle
+ IFileHandle handle;
+
/**
- * Create a TCF URL Connection using the specified url. The
- * format of this URL should be:
- * tcf:///<TCF_AGENT_ID>/remote/path/to/the/resource...
- * The stream protocol schema is designed in this way in order
- * to retrieve the agent peer ID without knowing the structure
- * of a TCF peer id.
+ * Create a TCF URL Connection using the specified url. The format of this
+ * URL should be: tcf:///<TCF_AGENT_ID>/remote/path/to/the/resource... The
+ * stream protocol schema is designed in this way in order to retrieve the
+ * agent peer ID without knowing the structure of a TCF peer id.
*
- * @param url The URL of the resource.
+ * @param url
+ * The URL of the resource.
*/
public TcfURLConnection(URL url) {
super(url);
@@ -57,16 +79,14 @@ public class TcfURLConnection extends URLConnection {
// /<TCF_AGENT_ID>/remote/path/to/the/resource...
path = url.getPath();
int slash = path.indexOf("/", 1); //$NON-NLS-1$
- String peerId;
if (slash != -1){
- peerId = path.substring(1, slash);
path = path.substring(slash);
if (path.matches("/[A-Za-z]:.*")) path = path.substring(1); //$NON-NLS-1$
- }else{
- peerId = path.substring(1);
}
//Get the peer using the peer id.
- peer = Protocol.getLocator().getPeers().get(peerId);
+ FSTreeNode node = FSModel.getInstance().getTreeNode(url);
+ if(node != null)
+ peer = node.peerNode.getPeer();
// Set default timeout.
setConnectTimeout(DEFAULT_CONNECT_TIMEOUT);
setOpenTimeout(DEFAULT_OPEN_TIMEOUT);
@@ -86,11 +106,13 @@ public class TcfURLConnection extends URLConnection {
/**
* Set the timeout for closing a file.
*
- * @param closeTimeout the timeout in milliseconds.
+ * @param closeTimeout
+ * the timeout in milliseconds.
*/
- public void setCloseTimeout(long closeTimeout) {
+ public void setCloseTimeout(int closeTimeout) {
this.closeTimeout = closeTimeout;
}
+
/**
* Get the timeout for opening a file.
*
@@ -103,29 +125,90 @@ public class TcfURLConnection extends URLConnection {
/**
* Set the timeout for opening a file.
*
- * @param openTimeout the timeout in milliseconds.
+ * @param openTimeout
+ * the timeout in milliseconds.
*/
- public void setOpenTimeout(long openTimeout) {
+ public void setOpenTimeout(int openTimeout) {
this.openTimeout = openTimeout;
}
+
+ /**
+ * Open a file on the remote file system for read/write and store the file handle.
+ *
+ * @throws IOException Opening file fails.
+ */
+ private void openFile() throws IOException {
+ if(peer == null)
+ throw new IOException(Messages.TcfURLConnection_NoSuchTcfAgent);
+ try {
+ // Open the channel
+ channel = TCFUtilities.openChannel(peer);
+ } catch (TCFChannelException e) {
+ throw new IOException(e.getLocalizedMessage());
+ }
+ if (channel != null) {
+ IFileSystem service = channel.getRemoteService(IFileSystem.class);
+ if (service != null) {
+ final Rendezvous rendezvous = new Rendezvous();
+ final FileSystemException[] errors = new FileSystemException[1];
+ // Open the file.
+ int open_flag = 0;
+ if (doInput)
+ open_flag |= IFileSystem.TCF_O_READ;
+ if (doOutput)
+ open_flag |= IFileSystem.TCF_O_WRITE;
+ service.open(path, open_flag, null, new DoneOpen() {
+ @Override
+ public void doneOpen(IToken token, FileSystemException error, IFileHandle hdl) {
+ errors[0] = error;
+ handle = hdl;
+ // Rendezvous
+ rendezvous.arrive();
+ }
+ });
+ try {
+ rendezvous.waiting(openTimeout);
+ } catch (InterruptedException e) {
+ throw new IOException(Messages.TcfURLConnection_OpenFileTimeout);
+ }
+ if (errors[0] != null) {
+ IOException exception = new IOException(errors[0].toString());
+ exception.initCause(errors[0]);
+ throw exception;
+ }
+ if (handle == null) {
+ throw new IOException(Messages.TcfURLConnection_NoFileHandleReturned);
+ }
+ } else {
+ throw new IOException(Messages.TcfURLConnection_NoFSServiceAvailable);
+ }
+ }
+ }
+
/*
* (non-Javadoc)
+ *
* @see java.net.URLConnection#connect()
*/
@Override
public void connect() throws IOException {
if (!connected) {
- inputStream = new TcfInputStream(peer, path);
- inputStream.setConnectTimeout(getConnectTimeout());
- inputStream.setOpenTimeout(getOpenTimeout());
- inputStream.setReadTimeout(getReadTimeout());
- inputStream.setCloseTimeout(getCloseTimeout());
+ openFile();
+ if (doInput) {
+ inputStream = new TcfInputStream(this);
+ inputStream.setTimeout(getReadTimeout());
+ }
+ if (doOutput) {
+ outputStream = new TcfOutputStream(this);
+ outputStream.setTimeout(getReadTimeout());
+ }
connected = true;
}
}
/*
* (non-Javadoc)
+ *
* @see java.net.URLConnection#getInputStream()
*/
@Override
@@ -134,4 +217,72 @@ public class TcfURLConnection extends URLConnection {
connect();
return inputStream;
}
+
+ /*
+ * (non-Javadoc)
+ * @see java.net.URLConnection#getOutputStream()
+ */
+ @Override
+ public OutputStream getOutputStream() throws IOException {
+ if (!connected)
+ connect();
+ return outputStream;
+ }
+
+ /**
+ * Close the stream, release its file handler and close
+ * the TCF channel used if possible.
+ *
+ * @param stream The stream either the input stream or the output stream.
+ * @throws IOException If closing file handle times out.
+ */
+ public synchronized void closeStream(Closeable stream) throws IOException {
+ boolean shouldClose = shouldCloseFileHandle(stream);
+ if (shouldClose) {
+ final Rendezvous rendezvous = new Rendezvous();
+ IFileSystem service = handle.getService();
+ service.close(handle, new DoneClose() {
+ @Override
+ public void doneClose(IToken token, FileSystemException error) {
+ rendezvous.arrive();
+ }
+ });
+ try {
+ rendezvous.waiting(closeTimeout);
+ } catch (InterruptedException e) {
+ throw new IOException(Messages.TcfURLConnection_CloseFileTimeout);
+ }
+ channel.close();
+ }
+ }
+
+ /**
+ * Decide if the file handle and the TCF channel should be closed if
+ * the specified stream is closed. If the stream is the last stream
+ * that depends on the file handle and the TCF channel, then it should
+ * be closed.
+ *
+ * @param stream The stream to be closed.
+ * @return true if the file handle and the TCF channel should be closed.
+ */
+ private boolean shouldCloseFileHandle(Closeable stream) {
+ boolean shouldClose = false;
+ if (stream == inputStream) {
+ if (doOutput) {
+ if (outputStream.closed) {
+ shouldClose = true;
+ }
+ } else {
+ shouldClose = true;
+ }
+ } else if (stream == outputStream) {
+ if (doInput) {
+ if (inputStream.closed)
+ shouldClose = true;
+ } else {
+ shouldClose = true;
+ }
+ }
+ return shouldClose;
+ }
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/CacheState.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/CacheState.java
new file mode 100644
index 000000000..a452855e4
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/CacheState.java
@@ -0,0 +1,22 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ * William Chen (Wind River)- [345552] Edit the remote files with a proper editor
+ *******************************************************************************/
+package org.eclipse.tm.te.tcf.filesystem.model;
+
+/**
+ * The enumeration that defines the states of a file's local cache, including "consistent", "modified",
+ * "outdated" and "conflict".
+ */
+public enum CacheState {
+ consistent, // Neither of the local file and the remote file has been changed since checking out.
+ modified, // The local file has changed while the remote file has not since checking out.
+ outdated, // The remote file has changed while the local file has not since checking out.
+ conflict // Both the local file and the remote file have changed since checking out.
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSModel.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSModel.java
index a92f26c88..b0c977f26 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSModel.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSModel.java
@@ -9,11 +9,18 @@
*******************************************************************************/
package org.eclipse.tm.te.tcf.filesystem.model;
+import java.io.File;
+import java.net.URL;
+import java.util.ArrayList;
+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.core.runtime.PlatformObject;
+import org.eclipse.tm.te.tcf.filesystem.internal.events.INodeStateListener;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.CacheManager;
/**
* The file system model implementation.
@@ -22,13 +29,37 @@ import org.eclipse.core.runtime.PlatformObject;
* model root node per peer id.
*/
public final class FSModel extends PlatformObject {
+ // Shared instance
+ private static final FSModel instance = new FSModel();
+ /**
+ * Get the shared instance of File System model.
+ * @return The File System Model.
+ */
+ public static FSModel getInstance(){
+ return instance;
+ }
/**
* The file system model root node cache. The keys
* are the peer id's.
*/
- private final Map<String, FSTreeNode> roots = new HashMap<String, FSTreeNode>();
+ private final Map<String, FSTreeNode> roots;
+ // The table mapping the local file to the fileNodes.
+ private Map<String, FSTreeNode> fileNodes;
+ // The table mapping the URL to the fileNodes.
+ private Map<URL, FSTreeNode> urlNodes;
+ // Node state listeners.
+ private List<INodeStateListener> listeners;
/**
+ * Create a File System Model.
+ */
+ private FSModel() {
+ roots = Collections.synchronizedMap(new HashMap<String, FSTreeNode>());
+ fileNodes = Collections.synchronizedMap(new HashMap<String, FSTreeNode>());
+ urlNodes = Collections.synchronizedMap(new HashMap<URL, FSTreeNode>());
+ listeners = Collections.synchronizedList(new ArrayList<INodeStateListener>());
+ }
+ /**
* Returns the file system model root node for the peer identified
* by the given peer id.
*
@@ -59,5 +90,74 @@ public final class FSModel extends PlatformObject {
*/
public void dispose() {
roots.clear();
+ fileNodes.clear();
+ urlNodes.clear();
+ }
+
+ /**
+ * Called to add an FSTreeNode to the two maps, i.e., the location-node map and
+ * the cache-location map.
+ * @param node The FSTreeNode to be added.
+ */
+ public void addNode(FSTreeNode node){
+ File cacheFile = CacheManager.getInstance().getCacheFile(node);
+ fileNodes.put(cacheFile.getAbsolutePath(), node);
+ urlNodes.put(node.getLocationURL(), node);
+ }
+
+ /**
+ * Get the FSTreeNode given its local file's path.
+ *
+ * @param path The local file's path.
+ * @return The FSTreeNode
+ */
+ public FSTreeNode getTreeNode(String path) {
+ return fileNodes.get(path);
+ }
+
+ /**
+ * Get the FSTreeNode given its URL location
+ * @param location the FSTreeNode's location
+ * @return the FSTreeNode
+ */
+ public FSTreeNode getTreeNode(URL location){
+ return urlNodes.get(location);
+ }
+
+ /**
+ * Add an INodeStateListener to the File System model if it is not
+ * in the listener list yet.
+ *
+ * @param listener The INodeStateListener to be added.
+ */
+ public void addNodeStateListener(INodeStateListener listener){
+ if(!listeners.contains(listener)){
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Remove the INodeStateListener from the File System model if it
+ * exists in the listener list.
+ *
+ * @param listener The INodeStateListener to be removed.
+ */
+ public void removeNodeStateListener(INodeStateListener listener){
+ if(listeners.contains(listener)){
+ listeners.remove(listener);
+ }
+ }
+
+ /**
+ * Fire a node state changed event with the specified node.
+ *
+ * @param node The node whose state has changed.
+ */
+ public void fireNodeStateChanged(FSTreeNode node){
+ synchronized(listeners){
+ for(INodeStateListener listener:listeners){
+ listener.stateChanged(node);
+ }
+ }
}
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSTreeNode.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSTreeNode.java
index 203a87963..cbb2f9a1d 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSTreeNode.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.filesystem/src/org/eclipse/tm/te/tcf/filesystem/model/FSTreeNode.java
@@ -15,33 +15,27 @@ package org.eclipse.tm.te.tcf.filesystem.model;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.UUID;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.PlatformObject;
-import org.eclipse.tm.tcf.protocol.IChannel;
-import org.eclipse.tm.tcf.protocol.IChannel.IChannelListener;
-import org.eclipse.tm.tcf.protocol.IToken;
import org.eclipse.tm.tcf.protocol.Protocol;
import org.eclipse.tm.tcf.services.IFileSystem;
-import org.eclipse.tm.tcf.services.IFileSystem.DoneUser;
-import org.eclipse.tm.tcf.services.IFileSystem.FileSystemException;
import org.eclipse.tm.te.tcf.filesystem.interfaces.IWindowsFileAttributes;
import org.eclipse.tm.te.tcf.filesystem.internal.UserAccount;
-import org.eclipse.tm.te.tcf.filesystem.internal.url.Rendezvous;
+import org.eclipse.tm.te.tcf.filesystem.internal.handlers.UserManager;
import org.eclipse.tm.te.tcf.filesystem.internal.url.TcfURLConnection;
import org.eclipse.tm.te.tcf.locator.interfaces.nodes.IPeerModel;
/**
* Target Explorer: Representation of a file system tree node.
* <p>
- * <b>Note:</b> Node construction and child list access is limited to
- * the TCF event dispatch thread.
+ * <b>Note:</b> Node construction and child list access is limited to the TCF
+ * event dispatch thread.
*/
public final class FSTreeNode extends PlatformObject {
- // The key to save and retrieve the user account in a peer model.
- private static final String USER_ACCOUNT_KEY = "user.account"; //$NON-NLS-1$
private final UUID uniqueId = UUID.randomUUID();
@@ -73,7 +67,7 @@ public final class FSTreeNode extends PlatformObject {
/**
* The tree node children.
*/
- private List<FSTreeNode> children = new ArrayList<FSTreeNode>();
+ private List<FSTreeNode> children;
/**
* Flag to mark once the children of the node got queried
@@ -90,10 +84,13 @@ public final class FSTreeNode extends PlatformObject {
*/
public FSTreeNode() {
super();
+ children = Collections.synchronizedList(new ArrayList<FSTreeNode>());
Assert.isTrue(Protocol.isDispatchThread());
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see java.lang.Object#hashCode()
*/
@Override
@@ -104,8 +101,9 @@ public final class FSTreeNode extends PlatformObject {
/**
* Returns the children list storage object.
* <p>
- * <b>Note:</b> This method must be called from within the TCF event dispatch thread only!
- *
+ * <b>Note:</b> This method must be called from within the TCF event
+ * dispatch thread only!
+ *
* @return The children list storage object.
*/
public final List<FSTreeNode> getChildren() {
@@ -113,18 +111,24 @@ public final class FSTreeNode extends PlatformObject {
return children;
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public final boolean equals(Object obj) {
+ if(this == obj)
+ return true;
if (obj instanceof FSTreeNode) {
- return uniqueId.equals(((FSTreeNode)obj).uniqueId);
+ return uniqueId.equals(((FSTreeNode) obj).uniqueId);
}
return super.equals(obj);
}
- /* (non-Javadoc)
+ /*
+ * (non-Javadoc)
+ *
* @see java.lang.Object#toString()
*/
@Override
@@ -137,6 +141,7 @@ public final class FSTreeNode extends PlatformObject {
/**
* Return if the node is a Windows file/folder node.
+ *
* @return true if it is a Windows node, or else false.
*/
public boolean isWindowsNode() {
@@ -145,6 +150,7 @@ public final class FSTreeNode extends PlatformObject {
/**
* Return if the node is a file.
+ *
* @return true if it is a file, or else false.
*/
public boolean isFile() {
@@ -153,6 +159,7 @@ public final class FSTreeNode extends PlatformObject {
/**
* Return if the node is a directory.
+ *
* @return true if it is a directory, or else false.
*/
public boolean isDirectory() {
@@ -161,7 +168,9 @@ public final class FSTreeNode extends PlatformObject {
/**
* Return if the attribute specified by the mask bit is turned on.
- * @param bit The attribute's mask bit.
+ *
+ * @param bit
+ * The attribute's mask bit.
* @return true if it is on, or else false.
*/
public boolean isWin32AttrOn(int bit) {
@@ -174,6 +183,7 @@ public final class FSTreeNode extends PlatformObject {
/**
* Return if this file/folder is hidden.
+ *
* @return true if it is hidden, or else false.
*/
public boolean isHidden() {
@@ -182,6 +192,7 @@ public final class FSTreeNode extends PlatformObject {
/**
* Return if this file/folder is read-only.
+ *
* @return true if it is read-only, or else false.
*/
public boolean isReadOnly() {
@@ -191,8 +202,9 @@ public final class FSTreeNode extends PlatformObject {
/**
* Get the location of a file/folder node using the format of the file
* system's platform.
- *
- * @param node The file/folder node.
+ *
+ * @param node
+ * The file/folder node.
* @return The location of the file/folder.
*/
public String getLocation() {
@@ -207,11 +219,12 @@ public final class FSTreeNode extends PlatformObject {
/**
* Get the location of a file/folder.
- *
- * @param cross If the format is cross-platform.
+ *
+ * @param cross
+ * If the format is cross-platform.
* @return The path to the file/folder.
*/
- private String getLocation(boolean cross) {
+ public String getLocation(boolean cross) {
if (parent == null)
return null;
String pLoc = parent.getLocation(cross);
@@ -223,23 +236,28 @@ public final class FSTreeNode extends PlatformObject {
}
/**
- * Get the URL of the file or folder. The URL's format
- * is created in the following way:
- * tcf:///<TCF_AGENT_ID>/remote/path/to/the/resource...
- * See {@link TcfURLConnection#TcfURLConnection(URL)}
- *
+ * Get the URL of the file or folder. The URL's format is created in the
+ * following way: tcf:///<TCF_AGENT_ID>/remote/path/to/the/resource... See
+ * {@link TcfURLConnection#TcfURLConnection(URL)}
+ *
* @return The URL of the file/folder.
* @throws MalformedURLException
*/
- public URL getLocationURL() throws MalformedURLException {
- String id = peerNode.getPeer().getID();
- String path = getLocation(true);
- String url = TcfURLConnection.PROTOCOL_SCHEMA+":///" + id + (isWindowsNode() ? "/" + path : path); //$NON-NLS-1$ //$NON-NLS-2$
- return new URL(url);
+ public URL getLocationURL() {
+ try {
+ String id = peerNode.getPeer().getID();
+ String path = getLocation(true);
+ String location = TcfURLConnection.PROTOCOL_SCHEMA + ":/" + id + (isWindowsNode() ? "/" + path : path); //$NON-NLS-1$ //$NON-NLS-2$
+ return new URL(location);
+ } catch (MalformedURLException e) {
+ assert false;
+ return null;
+ }
}
/**
* If this node is a root node.
+ *
* @return true if this node is a root node.
*/
public boolean isRoot() {
@@ -248,11 +266,11 @@ public final class FSTreeNode extends PlatformObject {
/**
* If this file is readable.
- *
+ *
* @return true if it is readable.
*/
public boolean isReadable() {
- UserAccount account = getUserAccount();
+ UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
if (account != null && attr != null) {
if (attr.uid == account.getEUID()) {
return (attr.permissions & IFileSystem.S_IRUSR) != 0;
@@ -267,11 +285,11 @@ public final class FSTreeNode extends PlatformObject {
/**
* If this file is writable.
- *
+ *
* @return true if it is writable.
*/
public boolean isWritable() {
- UserAccount account = getUserAccount();
+ UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
if (account != null && attr != null) {
if (attr.uid == account.getEUID()) {
return (attr.permissions & IFileSystem.S_IWUSR) != 0;
@@ -286,11 +304,11 @@ public final class FSTreeNode extends PlatformObject {
/**
* If this file is executable.
- *
+ *
* @return true if it is executable.
*/
public boolean isExecutable() {
- UserAccount account = getUserAccount();
+ UserAccount account = UserManager.getInstance().getUserAccount(peerNode);
if (account != null && attr != null) {
if (attr.uid == account.getEUID()) {
return (attr.permissions & IFileSystem.S_IXUSR) != 0;
@@ -302,108 +320,4 @@ public final class FSTreeNode extends PlatformObject {
}
return false;
}
-
- /**
- * Get the information of the client user account.
- *
- * @return The client user account's information.
- */
- private UserAccount getUserAccount() {
- UserAccount account = getUserAccount(peerNode);
- if (account == null) {
- final Rendezvous rendezvous = new Rendezvous();
- IChannel channel = peerNode.getPeer().openChannel();
- channel.addChannelListener(new IChannelListener() {
- @Override
- public void onChannelOpened() {
- rendezvous.arrive();
- }
-
- @Override
- public void onChannelClosed(Throwable error) {
- }
-
- @Override
- public void congestionLevel(int level) {
- }
- });
- try {
- rendezvous.waiting(5000L);
- } catch (InterruptedException e) {
- return null;
- }
- rendezvous.reset();
- IFileSystem service = channel.getRemoteService(IFileSystem.class);
- final UserAccount[] accounts = new UserAccount[1];
- service.user(new DoneUser() {
- @Override
- public void doneUser(IToken token, FileSystemException error,
- int real_uid, int effective_uid, int real_gid,
- int effective_gid, String home) {
- if (error == null) {
- accounts[0] = new UserAccount(real_uid, real_gid,
- effective_uid, effective_gid, home);
- }
- rendezvous.arrive();
- }
- });
- try {
- rendezvous.waiting(5000L);
- } catch (InterruptedException e) {
- return null;
- }
- if (accounts[0] == null)
- return null;
- account = accounts[0];
- setUserAccount(peerNode, account);
- }
- return account;
- }
-
- /**
- * Get the user account stored in the specified peer model using a key named
- * "user.account" defined by the constant USER_ACCOUNT_KEY.
- *
- * @param peer
- * The peer model from which the user account is retrieved.
- * @return The user account if it exists or null if not.
- */
- private UserAccount getUserAccount(final IPeerModel peer) {
- UserAccount account;
- if (Protocol.isDispatchThread()) {
- account = (UserAccount) peer.getProperty(USER_ACCOUNT_KEY);
- } else {
- final UserAccount[] accounts = new UserAccount[1];
- Protocol.invokeAndWait(new Runnable() {
- @Override
- public void run() {
- accounts[0] = (UserAccount) peer
- .getProperty(USER_ACCOUNT_KEY);
- }
- });
- account = accounts[0];
- }
- return account;
- }
-
- /**
- * Save the user account to the specified peer model using a key named
- * "user.account" defined by the constant USER_ACCOUNT_KEY.
- *
- * @param peer
- * The peer model to which the user account is saved.
- */
- private void setUserAccount(final IPeerModel peer, final UserAccount account) {
- assert peer != null && account != null;
- if (Protocol.isDispatchThread()) {
- peer.setProperty(USER_ACCOUNT_KEY, account);
- } else {
- Protocol.invokeAndWait(new Runnable() {
- @Override
- public void run() {
- peer.setProperty(USER_ACCOUNT_KEY, account);
- }
- });
- }
- }
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/activator/UIPlugin.java
index f252b3718..c95969bfe 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/activator/UIPlugin.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/activator/UIPlugin.java
@@ -76,18 +76,18 @@ public class UIPlugin extends AbstractUIPlugin {
@Override
protected void initializeImageRegistry(ImageRegistry registry) {
URL url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OBJ + "target.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_TARGET, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.TARGET, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OVR + "gold_ovr.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_GOLD_OVR, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.GOLD_OVR, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OVR + "green_ovr.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_GREEN_OVR, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.GREEN_OVR, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OVR + "grey_ovr.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_GREY_OVR, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.GREY_OVR, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OVR + "red_ovr.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_RED_OVR, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.RED_OVR, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_OVR + "redX_ovr.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_RED_X_OVR, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.RED_X_OVR, ImageDescriptor.createFromURL(url));
}
/**
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/ImageConsts.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/ImageConsts.java
index 477fb8574..4bd90b1ce 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/ImageConsts.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/ImageConsts.java
@@ -51,30 +51,30 @@ public interface ImageConsts {
/**
* The key to access the base target object image.
*/
- public static final String IMAGE_TARGET = "TargetObject"; //$NON-NLS-1$
+ public static final String TARGET = "TargetObject"; //$NON-NLS-1$
/**
* The key to access the target object gold overlay image.
*/
- public static final String IMAGE_GOLD_OVR = "GoldOverlay"; //$NON-NLS-1$
+ public static final String GOLD_OVR = "GoldOverlay"; //$NON-NLS-1$
/**
* The key to access the target object green overlay image.
*/
- public static final String IMAGE_GREEN_OVR = "GreenOverlay"; //$NON-NLS-1$
+ public static final String GREEN_OVR = "GreenOverlay"; //$NON-NLS-1$
/**
* The key to access the target object grey overlay image.
*/
- public static final String IMAGE_GREY_OVR = "GreyOverlay"; //$NON-NLS-1$
+ public static final String GREY_OVR = "GreyOverlay"; //$NON-NLS-1$
/**
* The key to access the target object red overlay image.
*/
- public static final String IMAGE_RED_OVR = "RedOverlay"; //$NON-NLS-1$
+ public static final String RED_OVR = "RedOverlay"; //$NON-NLS-1$
/**
* The key to access the target object red X overlay image.
*/
- public static final String IMAGE_RED_X_OVR = "RedXOverlay"; //$NON-NLS-1$
+ public static final String RED_X_OVR = "RedXOverlay"; //$NON-NLS-1$
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/LabelProviderDelegate.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/LabelProviderDelegate.java
index 4c8cf3f4d..01e2de5a0 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/LabelProviderDelegate.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/LabelProviderDelegate.java
@@ -64,7 +64,7 @@ public class LabelProviderDelegate extends LabelProvider implements ILabelDecora
@Override
public Image getImage(Object element) {
if (element instanceof IPeerModel) {
- return UIPlugin.getImage(ImageConsts.IMAGE_TARGET);
+ return UIPlugin.getImage(ImageConsts.TARGET);
}
return super.getImage(element);
diff --git a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/images/PeerImageDescriptor.java b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/images/PeerImageDescriptor.java
index b2d610eb9..2137fdfc0 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/images/PeerImageDescriptor.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.tcf.ui/src/org/eclipse/tm/te/tcf/ui/internal/navigator/images/PeerImageDescriptor.java
@@ -85,19 +85,19 @@ public class PeerImageDescriptor extends AbstractImageDescriptor {
drawCentered(baseImage, width, height);
if (state == IPeerModelProperties.STATE_UNKNOWN) { /* unknown */
- drawBottomRight(ImageConsts.IMAGE_GREY_OVR);
+ drawBottomRight(ImageConsts.GREY_OVR);
}
else if (state == IPeerModelProperties.STATE_REACHABLE) { /* not connected, but reachable */
- drawBottomRight(ImageConsts.IMAGE_GOLD_OVR);
+ drawBottomRight(ImageConsts.GOLD_OVR);
}
else if (state == IPeerModelProperties.STATE_CONNECTED) { /* connected */
- drawBottomRight(ImageConsts.IMAGE_GREEN_OVR);
+ drawBottomRight(ImageConsts.GREEN_OVR);
}
else if (state == IPeerModelProperties.STATE_NOT_REACHABLE) { /* not connected, not reachable */
- drawBottomRight(ImageConsts.IMAGE_RED_OVR);
+ drawBottomRight(ImageConsts.RED_OVR);
}
else if (state == IPeerModelProperties.STATE_ERROR) { /* not connected, error */
- drawBottomRight(ImageConsts.IMAGE_RED_X_OVR);
+ drawBottomRight(ImageConsts.RED_X_OVR);
}
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.controls/build.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.controls/build.properties
index aa1a00826..c5906f02c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.controls/build.properties
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.controls/build.properties
@@ -3,3 +3,4 @@ output.. = bin/
bin.includes = META-INF/,\
.,\
plugin.properties
+jars.extra.classpath = platform:/plugin/org.eclipse.core.resources
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.forms/pom.xml b/target_explorer/plugins/org.eclipse.tm.te.ui.forms/pom.xml
index 5d2830829..4a3a44eb7 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.forms/pom.xml
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.forms/pom.xml
@@ -12,6 +12,6 @@
</parent>
<version>1.0.0.qualifier</version>
- <artifactId>org.eclipse.tm.te.ui.swt</artifactId>
+ <artifactId>org.eclipse.tm.te.ui.forms</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/pom.xml b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/pom.xml
index 4a3a44eb7..5d2830829 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/pom.xml
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/pom.xml
@@ -12,6 +12,6 @@
</parent>
<version>1.0.0.qualifier</version>
- <artifactId>org.eclipse.tm.te.ui.forms</artifactId>
+ <artifactId>org.eclipse.tm.te.ui.swt</artifactId>
<packaging>eclipse-plugin</packaging>
</project>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java
index e5f5ecb6e..23f6902aa 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractCheckBoxCellPaintListener.java
@@ -46,7 +46,7 @@ public abstract class AbstractCheckBoxCellPaintListener extends AbstractCellPain
}
/* (non-Javadoc)
- * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image)
+ * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image)
*/
@Override
protected Point getPaintOrigin(Event event, Image image) {
@@ -60,7 +60,7 @@ public abstract class AbstractCheckBoxCellPaintListener extends AbstractCellPain
}
/* (non-Javadoc)
- * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int)
+ * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int)
*/
@Override
protected Image getImageToDraw(Item item, int columnIndex) {
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java
index 94f4cd916..84fac2862 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.swt/src/org/eclipse/tm/te/ui/swt/listener/AbstractDecorationCellPaintListener.java
@@ -40,7 +40,7 @@ public abstract class AbstractDecorationCellPaintListener extends AbstractCellPa
}
/* (non-Javadoc)
- * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image)
+ * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getPaintOrigin(org.eclipse.swt.widgets.Event, org.eclipse.swt.graphics.Image)
*/
@Override
protected Point getPaintOrigin(Event event, Image image) {
@@ -48,7 +48,7 @@ public abstract class AbstractDecorationCellPaintListener extends AbstractCellPa
}
/* (non-Javadoc)
- * @see com.windriver.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int)
+ * @see org.eclipse.tm.te.ui.swt.listener.AbstractCellPaintListener#getImageToDraw(org.eclipse.swt.widgets.Item, int)
*/
@Override
protected Image getImageToDraw(Item item, int columnIndex) {
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.classpath b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.classpath
new file mode 100644
index 000000000..8a8f1668c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.classpath
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+ <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options
new file mode 100644
index 000000000..2ad378b66
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.options
@@ -0,0 +1 @@
+org.eclipse.tm.te.ui.terminals/debugmode = 0
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.project b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.project
new file mode 100644
index 000000000..ad1ea71d6
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.project
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.tm.te.ui.terminals</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.ManifestBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.pde.SchemaBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.pde.PluginNature</nature>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.settings/org.eclipse.jdt.core.prefs b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 000000000..ea56f8105
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,82 @@
+#Tue Oct 04 14:39:47 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
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF
new file mode 100644
index 000000000..dd35637dc
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/META-INF/MANIFEST.MF
@@ -0,0 +1,22 @@
+Manifest-Version: 1.0
+Bundle-ManifestVersion: 2
+Bundle-Name: %pluginName
+Bundle-SymbolicName: org.eclipse.tm.te.ui.terminals;singleton:=true
+Bundle-Version: 1.0.0.qualifier
+Bundle-Activator: org.eclipse.tm.te.ui.terminals.activator.UIPlugin
+Bundle-Vendor: %providerName
+Require-Bundle: org.eclipse.core.runtime;bundle-version="3.7.0",
+ org.eclipse.core.expressions;bundle-version="3.4.300",
+ org.eclipse.core.resources;bundle-version="3.7.100";resolution:=optional,
+ org.eclipse.ui;bundle-version="3.7.0",
+ org.eclipse.ui.ide;bundle-version="3.7.0",
+ org.eclipse.tm.terminal;bundle-version="3.1.1",
+ org.eclipse.tm.terminal.telnet;bundle-version="2.1.0",
+ org.eclipse.tm.terminal.view;bundle-version="2.2.0",
+ org.eclipse.tm.te.runtime;bundle-version="1.0.0",
+ org.eclipse.tm.te.ui;bundle-version="1.0.0",
+ org.eclipse.tm.te.ui.swt;bundle-version="1.0.0",
+ org.eclipse.cdt.core;bundle-version="5.3.0"
+Bundle-RequiredExecutionEnvironment: JavaSE-1.6
+Bundle-ActivationPolicy: lazy
+Bundle-Localization: plugin
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/build.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/build.properties
new file mode 100644
index 000000000..73a5119ed
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/build.properties
@@ -0,0 +1,6 @@
+source.. = src/
+output.. = bin/
+bin.includes = META-INF/,\
+ .,\
+ plugin.properties,\
+ plugin.xml
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.properties
new file mode 100644
index 000000000..faf90fdb0
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.properties
@@ -0,0 +1,23 @@
+##################################################################################
+# Copyright (c) 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 v1.0 which accompanies this distribution, and is
+# available at http://www.eclipse.org/legal/epl-v10.html
+#
+# Contributors:
+# Wind River Systems - initial API and implementation
+##################################################################################
+
+pluginName = Target Explorer, Terminals
+providerName = Eclipse.org
+
+# ----- Terminals View -----
+
+TerminalsView.name=Terminals
+
+# ----- Terminal Connectors -----
+
+TerminalConnector.process=Process
+TerminalConnector.streams=Streams Connector (hidden)
+
+# ----- Commands and Menu contributions -----
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml
new file mode 100644
index 000000000..31dc3d21b
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/plugin.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+<!-- View contributions -->
+ <extension point="org.eclipse.ui.views">
+ <view
+ category="org.eclipse.tm.te.ui.views.category"
+ class="org.eclipse.tm.te.ui.terminals.view.TerminalsView"
+ icon="platform:/plugin/org.eclipse.ui.console/icons/full/eview16/console_view.gif"
+ id="org.eclipse.tm.te.ui.terminals.TerminalsView"
+ name="%TerminalsView.name">
+ </view>
+ </extension>
+
+<!-- Perspective extension contributions -->
+ <extension point="org.eclipse.ui.perspectiveExtensions">
+ <perspectiveExtension targetID="*">
+ <view
+ id="org.eclipse.tm.te.ui.terminals.TerminalsView"
+ minimized="false"
+ relationship="stack"
+ relative="org.eclipse.ui.views.TaskList"
+ visible="false">
+ </view>
+ </perspectiveExtension>
+ </extension>
+
+<!-- Terminal connector contributions -->
+ <extension point="org.eclipse.tm.terminal.terminalConnectors">
+ <connector
+ name="%TerminalConnector.process"
+ id="org.eclipse.tm.te.ui.terminals.ProcessConnector"
+ class="org.eclipse.tm.te.ui.terminals.process.ProcessConnector"/>
+
+ <connector
+ name="%TerminalConnector.streams"
+ id="org.eclipse.tm.te.ui.terminals.StreamsConnector"
+ hidden="true"
+ class="org.eclipse.tm.te.ui.terminals.streams.StreamsConnector"/>
+ </extension>
+
+<!-- Preferences contributions -->
+ <extension point="org.eclipse.core.runtime.preferences">
+ <initializer class="org.eclipse.tm.te.ui.terminals.internal.PreferenceInitializer"/>
+ </extension>
+
+</plugin>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/pom.xml b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/pom.xml
new file mode 100644
index 000000000..26a4b4bbd
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/pom.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
+ xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+ <modelVersion>4.0.0</modelVersion>
+
+ <parent>
+ <groupId>org.eclipse.tcf</groupId>
+ <artifactId>tcf-parent</artifactId>
+ <version>0.5.0-SNAPSHOT</version>
+ <relativePath>../../../pom.xml</relativePath>
+ </parent>
+
+ <version>1.0.0.qualifier</version>
+ <artifactId>org.eclipse.tm.te.ui.terminals</artifactId>
+ <packaging>eclipse-plugin</packaging>
+</project>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java
new file mode 100644
index 000000000..54d2ecee4
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/AbstractAction.java
@@ -0,0 +1,184 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.actions;
+
+import java.util.Collections;
+
+import org.eclipse.core.commands.Command;
+import org.eclipse.core.commands.ExecutionEvent;
+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.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.nls.Messages;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderToolbarHandler;
+import org.eclipse.ui.ISources;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.commands.ICommandService;
+
+/**
+ * Abstract terminal action wrapper implementation.
+ */
+@SuppressWarnings("restriction")
+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
+ * <code>null</code>.
+ * @param id
+ * The terminal action id. Must not be <code>null</code>.
+ */
+ 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.
+ * <p>
+ * <b>Node:</b> If the provided data node is <code>null</code>, the method will trigger
+ * the command with an empty selection.
+ *
+ * @param data The terminal custom data node or <code>null</code>.
+ */
+ 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()) {
+ // Construct a selection element
+ IStructuredSelection selection = data != null ? new StructuredSelection(data) : new StructuredSelection();
+ // Construct the application context
+ EvaluationContext context = new EvaluationContext(null, 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);
+ // Construct the execution event
+ ExecutionEvent execEvent = new ExecutionEvent(command, Collections.EMPTY_MAP, this, context);
+ // And execute the event
+ try {
+ command.executeWithChecks(execEvent);
+ } 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 <code>null</code>.
+ */
+ 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 <code>null</code>.
+ * @return <code>True</code> to enable the action, <code>false</code> otherwise.
+ */
+ protected boolean checkEnableAction(Object data) {
+ return data != null;
+ }
+
+ /**
+ * Returns if the action is a separator. Returning <code>true</code> here
+ * means that an additional separator toolbar element is added right or
+ * above of the action.
+ *
+ * @return <code>True</code> if the action is separating the parent contribution manager, <code>false</code> otherwise.
+ */
+ public boolean isSeparator() {
+ return false;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java
new file mode 100644
index 000000000..73d9fd237
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/actions/TabScrollLockAction.java
@@ -0,0 +1,58 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.tm.internal.terminal.actions.ActionMessages;
+import org.eclipse.tm.internal.terminal.control.ITerminalViewControl;
+import org.eclipse.tm.internal.terminal.control.actions.AbstractTerminalAction;
+import org.eclipse.tm.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.interfaces.ImageConsts;
+
+/**
+ * Terminal console tab scroll lock action.
+ */
+@SuppressWarnings("restriction")
+public class TabScrollLockAction extends AbstractTerminalAction {
+
+ /**
+ * Constructor.
+ */
+ public TabScrollLockAction() {
+ super(null, TabScrollLockAction.class.getName(), IAction.AS_RADIO_BUTTON);
+
+ setupAction(ActionMessages.SCROLL_LOCK_0,
+ ActionMessages.SCROLL_LOCK_1,
+ 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(getTarget() != null && aboutToShow);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java
new file mode 100644
index 000000000..a919f570e
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/activator/UIPlugin.java
@@ -0,0 +1,143 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.activator;
+
+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.swt.graphics.Image;
+import org.eclipse.tm.te.runtime.preferences.ScopedEclipsePreferences;
+import org.eclipse.tm.te.runtime.tracing.TraceHandler;
+import org.eclipse.tm.te.ui.terminals.interfaces.ImageConsts;
+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;
+
+ private static ScopedEclipsePreferences scopedPreferences = null;
+ // The trace handler instance
+ private static 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 null;
+ }
+
+ /**
+ * Return the scoped preferences for this plugin.
+ */
+ 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) {
+ Bundle bundle = Platform.getBundle("org.eclipse.ui.console"); //$NON-NLS-1$
+ if (bundle != null && (bundle.getState() == Bundle.RESOLVED || bundle.getState() == Bundle.ACTIVE)) {
+ URL url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_EVIEW + "console_view.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.VIEW_Terminals, ImageDescriptor.createFromURL(url));
+
+ url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_CLCL + "lock_co.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.ACTION_ScrollLock_Hover, ImageDescriptor.createFromURL(url));
+ url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_ELCL + "lock_co.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.ACTION_ScrollLock_Enabled, ImageDescriptor.createFromURL(url));
+ url = bundle.getEntry(ImageConsts.IMAGE_DIR_ROOT + "full/" + ImageConsts.IMAGE_DIR_DLCL + "lock_co.gif"); //$NON-NLS-1$ //$NON-NLS-2$
+ registry.put(ImageConsts.ACTION_ScrollLock_Disabled, ImageDescriptor.createFromURL(url));
+ }
+ }
+
+ /**
+ * Loads the image registered under the specified key from the image
+ * registry and returns the <code>Image</code> object instance.
+ *
+ * @param key The key the image is registered with.
+ * @return The <code>Image</code> object instance or <code>null</code>.
+ */
+ 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 <code>ImageDescriptor</code> object instance.
+ *
+ * @param key The key the image is registered with.
+ * @return The <code>ImageDescriptor</code> object instance or <code>null</code>.
+ */
+ public static ImageDescriptor getImageDescriptor(String key) {
+ return getDefault().getImageRegistry().getDescriptor(key);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java
new file mode 100644
index 000000000..1eb267f5d
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/events/SelectionChangedBroadcastEvent.java
@@ -0,0 +1,77 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.events;
+
+import java.util.EventObject;
+
+import org.eclipse.jface.viewers.SelectionChangedEvent;
+import org.eclipse.tm.te.runtime.events.EventManager;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager;
+
+/**
+ * Terminal console selection changed broadcast event. The event is typically fired
+ * by a terminal console tab folder manager to signal a tab switch to all listeners.
+ */
+public class SelectionChangedBroadcastEvent extends EventObject {
+ private static final long serialVersionUID = -4970244776543572896L;
+
+ // The selection changed event to broadcast
+ private final SelectionChangedEvent selectionChangedEvent;
+
+ /**
+ * Constructor.
+ *
+ * @param source The event source. Must not be <code>null</code>.
+ * @param selectionChangedEvent The selection changed event or <code>null</code>.
+ */
+ public SelectionChangedBroadcastEvent(TabFolderManager source, SelectionChangedEvent selectionChangedEvent) {
+ super(source);
+ this.selectionChangedEvent = selectionChangedEvent;
+ }
+
+ /**
+ * Convenience method to return the source tab folder manager.
+ *
+ * @return The source tab folder manager.
+ */
+ public TabFolderManager getSourceTabFolderManager() {
+ return (TabFolderManager)getSource();
+ }
+
+ /**
+ * Returns the broadcasted selection changed event.
+ *
+ * @return The broadcasted selection changed event or <code>null</code>.
+ */
+ public SelectionChangedEvent getSelectionChangedEvent() {
+ return selectionChangedEvent;
+ }
+
+ /* (non-Javadoc)
+ * @see java.util.EventObject#toString()
+ */
+ @Override
+ public String toString() {
+ StringBuilder toString = new StringBuilder(getClass().getName());
+
+ String prefix = ""; //$NON-NLS-1$
+ // if debugging the event, formating them a little bit better readable.
+ if (EventManager.isTracingEnabled())
+ prefix = "\n\t\t"; //$NON-NLS-1$
+
+ toString.append(prefix + "source="); //$NON-NLS-1$
+ toString.append(source);
+ toString.append("," + prefix + "selectionChangedEvent="); //$NON-NLS-1$ //$NON-NLS-2$
+ toString.append(selectionChangedEvent);
+ toString.append("}"); //$NON-NLS-1$
+
+ return toString.toString();
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java
new file mode 100644
index 000000000..b07359704
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IPreferenceKeys.java
@@ -0,0 +1,25 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.interfaces;
+
+/**
+ * Terminals plug-in preference key definitions.
+ */
+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$
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java
new file mode 100644
index 000000000..3c856f0c1
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ITerminalsView.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.interfaces;
+
+import org.eclipse.ui.IViewPart;
+
+/**
+ * Terminals view public interface.
+ */
+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 <code>null</code> if none is associated.
+ */
+ public String getContextHelpId();
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java
new file mode 100644
index 000000000..87fc1307c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/IUIConstants.java
@@ -0,0 +1,21 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.interfaces;
+
+/**
+ * Terminals common UI constants.
+ */
+public interface IUIConstants {
+ /**
+ * The view id of the terminals view.
+ */
+ public static final String ID = "org.eclipse.tm.te.ui.terminals.TerminalsView"; //$NON-NLS-1$
+
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java
new file mode 100644
index 000000000..0934c14c8
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/interfaces/ImageConsts.java
@@ -0,0 +1,65 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.interfaces;
+
+/**
+ * Target Explorer: Image registry constants.
+ */
+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 terminal consoles 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$
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java
new file mode 100644
index 000000000..8cb06cc34
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/PreferenceInitializer.java
@@ -0,0 +1,37 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.internal;
+
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.tm.te.runtime.preferences.ScopedEclipsePreferences;
+import org.eclipse.tm.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.interfaces.IPreferenceKeys;
+
+/**
+ * Terminals default preferences initializer.
+ */
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+ /**
+ * Constructor.
+ */
+ public PreferenceInitializer() {
+ }
+
+ /* (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);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java
new file mode 100644
index 000000000..250776a6d
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/internal/SettingsStore.java
@@ -0,0 +1,52 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.internal;
+
+import org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore;
+import org.eclipse.tm.te.runtime.properties.PropertiesContainer;
+
+/**
+ * Simple default Terminal settings store implementation keeping the settings
+ * within memory.
+ */
+@SuppressWarnings("restriction")
+public class SettingsStore extends PropertiesContainer implements ISettingsStore {
+
+ /**
+ * Constructor.
+ */
+ public SettingsStore() {
+ }
+
+ /* (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) {
+ String value = getStringProperty(key);
+ return value != null ? value : defaultValue;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsStore#get(java.lang.String)
+ */
+ @Override
+ public String get(String key) {
+ return getStringProperty(key);
+ }
+
+ /* (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) {
+ setProperty(key, value);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java
new file mode 100644
index 000000000..3fd6ffc32
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConnectorManager.java
@@ -0,0 +1,198 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.manager;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.cdt.utils.pty.PTY;
+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.internal.terminal.telnet.TelnetSettings;
+import org.eclipse.tm.te.ui.terminals.internal.SettingsStore;
+import org.eclipse.tm.te.ui.terminals.process.ProcessSettings;
+import org.eclipse.tm.te.ui.terminals.streams.StreamsSettings;
+
+
+/**
+ * Terminal connector manager implementation.
+ */
+@SuppressWarnings("restriction")
+public class ConnectorManager {
+
+ /*
+ * Thread save singleton instance creation.
+ */
+ private static class LazyInstanceHolder {
+ public static ConnectorManager instance = new ConnectorManager();
+ }
+
+ /**
+ * Returns the singleton instance for the terminal connector manager.
+ */
+ public static ConnectorManager getInstance() {
+ return LazyInstanceHolder.instance;
+ }
+
+ /**
+ * Constructor.
+ */
+ ConnectorManager() {
+ super();
+ }
+
+ /**
+ * Creates a terminal connector object based on the given telnet server attributes.
+ * <p>
+ * The telnet server attributes must contain 2 elements:
+ * <ul>
+ * <li>attributes[0] --> telnet server host name</li>
+ * <li>attributes[1] --> telnet port</li>
+ * <li>attributes[2] --> timeout</li>
+ * </ul>
+ *
+ * @param attributes The telnet server attributes. Must not be <code>null</code> and must have at least two elements.
+ * @param portOffset Offset to add to the port.
+ *
+ * @return The terminal connector object instance or <code>null</code>.
+ */
+ public ITerminalConnector createTelnetConnector(String[] attributes) {
+ return createTelnetConnector(attributes, 0);
+ }
+
+ /**
+ * Creates a terminal connector object based on the given telnet server attributes.
+ * <p>
+ * The telnet server attributes must contain at least 2 elements:
+ * <ul>
+ * <li>attributes[0] --> telnet server host name</li>
+ * <li>attributes[1] --> telnet port</li>
+ * <li>attributes[2] --> timeout (optional)</li>
+ * </ul>
+ *
+ * @param attributes The telnet server attributes. Must not be <code>null</code> and must have at least two elements.
+ * @param portOffset Offset to add to the port.
+ *
+ * @return The terminal connector object instance or <code>null</code>.
+ */
+ public ITerminalConnector createTelnetConnector(String[] attributes, int portOffset) {
+ assert attributes != null && attributes.length >= 2;
+
+ final String serverName = attributes[0];
+ final String serverPort = Integer.toString(Integer.decode(attributes[1]).intValue() + portOffset);
+ final String timeout = attributes.length >= 3 ? attributes[2] : null;
+
+ // Construct the terminal settings store
+ ISettingsStore store = new SettingsStore();
+
+ // Construct the telnet settings
+ TelnetSettings telnetSettings = new TelnetSettings();
+ telnetSettings.setHost(serverName);
+ telnetSettings.setNetworkPort(serverPort);
+ if (timeout != null) {
+ telnetSettings.setTimeout(timeout);
+ }
+ // And save the settings to the store
+ telnetSettings.save(store);
+
+ // Construct the terminal connector instance
+ ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector("org.eclipse.tm.internal.terminal.telnet.TelnetConnector"); //$NON-NLS-1$
+ if (connector != null) {
+ // Apply default settings
+ connector.makeSettingsPage();
+ // And load the real settings
+ connector.load(store);
+ }
+
+ return connector;
+ }
+
+ /**
+ * Creates a terminal connector object based on the given process image
+ * and the corresponding process object.
+ *
+ * @param connectorTypeId Optional ID of the specific process connector implementation to use.
+ * If <code>null</code>, the default process connector will be used.
+ * @param image The process image path. Must not be <code>null</code>.
+ * @param arguments The process arguments or <code>null</code>.
+ * @param process The process. Must not be <code>null</code>.
+ * @param pty The pseudo terminal or <code>null</code>.
+ * @param localEcho <code>True</code> if the terminal widget local echo shall be enabled, <code>false</code> otherwise.
+ *
+ * @return The terminal connector object instance or <code>null</code>.
+ */
+ public ITerminalConnector createProcessConnector(String connectorTypeId, final String image, final String arguments, final Process process, PTY pty, boolean localEcho) {
+ assert image != null || process != null;
+
+ // Normalize the process connector id
+ if (connectorTypeId == null) connectorTypeId = "org.eclipse.tm.te.ui.terminals.ProcessConnector"; //$NON-NLS-1$
+
+ // 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);
+ // And save the settings to the store
+ processSettings.save(store);
+
+ // Construct the terminal connector instance
+ ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector(connectorTypeId);
+ if (connector != null) {
+ // Apply default settings
+ connector.makeSettingsPage();
+ // And load the real settings
+ connector.load(store);
+ }
+
+ return connector;
+ }
+
+ /**
+ * Creates a terminal connector object based on the given stream objects.
+ *
+ * @param stdin The stdin stream or <code>null</code>.
+ * @param stdout The stdout stream or <code>null</code>.
+ * @param stderr The stderr stream or <code>null</code>.
+ * @param localEcho <code>True</code> if the terminal widget local echo shall be enabled, <code>false</code> otherwise.
+ *
+ * @return The terminal connector object instance or <code>null</code>.
+ */
+ public ITerminalConnector createStreamsConnector(OutputStream stdin, InputStream stdout, InputStream stderr, boolean localEcho) {
+
+ // 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);
+ // And save the settings to the store
+ streamsSettings.save(store);
+
+ // Construct the terminal connector instance
+ ITerminalConnector connector = TerminalConnectorExtension.makeTerminalConnector("org.eclipse.tm.te.ui.terminals.StreamsConnector"); //$NON-NLS-1$
+ if (connector != null) {
+ // Apply default settings
+ connector.makeSettingsPage();
+ // And load the real settings
+ connector.load(store);
+ }
+
+ return connector;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java
new file mode 100644
index 000000000..e2ee3c91d
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/manager/ConsoleManager.java
@@ -0,0 +1,300 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.manager;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.core.runtime.IStatus;
+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.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.interfaces.IPreferenceKeys;
+import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView;
+import org.eclipse.tm.te.ui.terminals.interfaces.IUIConstants;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager;
+import org.eclipse.tm.te.ui.terminals.view.TerminalsView;
+import org.eclipse.ui.IPerspectiveDescriptor;
+import org.eclipse.ui.IPerspectiveListener;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IViewReference;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.PartInitException;
+import org.eclipse.ui.PerspectiveAdapter;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * Terminals console manager.
+ */
+@SuppressWarnings("restriction")
+public class ConsoleManager {
+ // Reference to the perspective listener instance
+ private final IPerspectiveListener perspectiveListener;
+
+ // Internal perspective listener implementation
+ static class TerminalConsoleManagerPerspectiveListener extends PerspectiveAdapter {
+ private final List<IViewReference> references = new ArrayList<IViewReference>();
+
+ /* (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<IViewReference> oldReferences = new ArrayList<IViewReference>(references);
+
+ // Get the current list of view references
+ List<IViewReference> references = new ArrayList<IViewReference>(Arrays.asList(page.getViewReferences()));
+ for (IViewReference reference : oldReferences) {
+ if (references.contains(reference)) continue;
+ // Previous visible terminal 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);
+ }
+ }
+ }
+ }
+
+ /*
+ * 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();
+
+ // Attach the perspective listener
+ perspectiveListener = new TerminalConsoleManagerPerspectiveListener();
+ if (PlatformUI.isWorkbenchRunning() && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getActiveWorkbenchWindow() != null) {
+ PlatformUI.getWorkbench().getActiveWorkbenchWindow().addPerspectiveListener(perspectiveListener);
+ }
+ }
+
+ /**
+ * Returns the active workbench window page if the workbench is still running.
+ *
+ * @return The active workbench window page or <code>null</code>
+ */
+ 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.
+ * <p>
+ * <b>Note:</b> The method must be called within the UI thread.
+ *
+ * @param id The terminal console view id or <code>null</code> to show the default terminal console view.
+ * @return The console view instance if available or <code>null</code> otherwise.
+ */
+ public ITerminalsView findConsoleView(String id) {
+ assert Display.findDisplay(Thread.currentThread()) != null;
+
+ ITerminalsView view = null;
+
+ // Get the active workbench page
+ IWorkbenchPage page = getActiveWorkbenchPage();
+ if (page != null) {
+ // Look for the view
+ IViewPart part = page.findView(id != null ? id : IUIConstants.ID);
+ // Check the interface
+ if (part instanceof ITerminalsView) {
+ view = (ITerminalsView)part;
+ }
+ }
+
+ return view;
+ }
+
+ /**
+ * Show the terminal console view specified by the given id.
+ * <p>
+ * <b>Note:</b> The method must be called within the UI thread.
+ *
+ * @param id The terminal console view id or <code>null</code> to show the default terminal console view.
+ */
+ public void showConsoleView(String id) {
+ assert Display.findDisplay(Thread.currentThread()) != null;
+
+ // Get the active workbench page
+ IWorkbenchPage page = getActiveWorkbenchPage();
+ if (page != null) {
+ try {
+ // show the view
+ IViewPart part = page.showView(id != null ? id : IUIConstants.ID);
+ // and force the view to the foreground
+ page.bringToTop(part);
+ } catch (PartInitException e) {
+ IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(),
+ e.getLocalizedMessage(), e);
+ UIPlugin.getDefault().getLog().log(status);
+ }
+ }
+ }
+
+ /**
+ * Bring the terminal console view, specified by the given id, to the top of the view stack.
+ *
+ * @param id The terminal console view id or <code>null</code> to show the default terminal console view.
+ * @param activate If <code>true</code> activate the console view.
+ */
+ private void bringToTop(String id, boolean activate) {
+ // Get the active workbench page
+ IWorkbenchPage page = getActiveWorkbenchPage();
+ if (page != null) {
+ // Look for the view
+ IViewPart part = page.findView(id != null ? id : IUIConstants.ID);
+ if (part != null) {
+ if (activate) {
+ page.activate(part);
+ }
+ else {
+ page.bringToTop(part);
+ }
+ } else if (activate) showConsoleView(id != null ? id : IUIConstants.ID);
+ }
+ }
+
+ /**
+ * Opens the console with the given title and connector.
+ * <p>
+ * <b>Note:</b> The method must be called within the UI thread.
+ *
+ * @param id The terminal console view id or <code>null</code> to show the default terminal console view.
+ * @param title The console title. Must not be <code>null</code>.
+ * @param connector The terminal connector. Must not be <code>null</code>.
+ * @param data The custom terminal data node or <code>null</code>.
+ * @param activate If <code>true</code> activate the console view.
+ */
+ public void openConsole(String id, String title, ITerminalConnector connector, Object data, boolean activate) {
+ assert title != null && connector != null;
+ assert Display.findDisplay(Thread.currentThread()) != null;
+
+ // make the consoles view visible
+ bringToTop(id, activate);
+
+ // Get the console view
+ ITerminalsView view = findConsoleView(id);
+ if (view == null) return;
+
+ // Get the tab folder manager associated with the view
+ TabFolderManager manager = (TabFolderManager)view.getAdapter(TabFolderManager.class);
+ if (manager == null) return;
+
+ // Lookup an existing console first
+ CTabItem item = findConsole(id, title, connector, data);
+
+ // If no existing console exist -> Create the tab item
+ if (item == null) {
+ // If configured, check all existing tab items if they are associated
+ // with terminated consoles
+ if (UIPlugin.getScopedPreferences().getBoolean(IPreferenceKeys.PREF_REMOVE_TERMINATED_TERMINALS)) {
+ manager.removeTerminatedItems();
+ }
+
+ // Create a new tab item
+ item = manager.createTabItem(title, connector, data);
+ }
+ // If still null, something went wrong
+ if (item == null) {
+ return;
+ }
+
+ // Make the item the active console
+ manager.bringToTop(item);
+
+ // Show the tab folder page
+ view.switchToTabFolderControl();
+ }
+
+ /**
+ * Lookup a console with the given title and the given terminal connector.
+ * <p>
+ * <b>Note:</b> The method must be called within the UI thread.
+ * <b>Note:</b> The method will handle unified console titles itself.
+ *
+ * @param id The terminal console view id or <code>null</code> to show the default terminal console view.
+ * @param title The console title. Must not be <code>null</code>.
+ * @param connector The terminal connector. Must not be <code>null</code>.
+ * @param data The custom terminal data node or <code>null</code>.
+ *
+ * @return The corresponding console tab item or <code>null</code>.
+ */
+ public CTabItem findConsole(String id, String title, ITerminalConnector connector, Object data) {
+ assert title != null && connector != null;
+ assert Display.findDisplay(Thread.currentThread()) != null;
+
+ // Get the console view
+ ITerminalsView view = findConsoleView(id);
+ 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);
+ }
+
+ /**
+ * Close the console with the given title and the given terminal connector.
+ * <p>
+ * <b>Note:</b> The method must be called within the UI thread.
+ * <b>Note:</b> The method will handle unified console titles itself.
+ *
+ * @param title The console title. Must not be <code>null</code>.
+ * @param connector The terminal connector. Must not be <code>null</code>.
+ * @param data The custom terminal data node or <code>null</code>.
+ */
+ public void closeConsole(String id, String title, ITerminalConnector connector, Object data) {
+ assert title != null && connector != null;
+ assert Display.findDisplay(Thread.currentThread()) != null;
+
+ // Lookup the console
+ CTabItem console = findConsole(id, title, connector, data);
+ // If found, dispose the console
+ if (console != null) console.dispose();
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java
new file mode 100644
index 000000000..c5cf6b22f
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.java
@@ -0,0 +1,47 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.nls;
+
+import org.eclipse.osgi.util.NLS;
+
+/**
+ * Terminals 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.te.ui.terminals.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 AbstractAction_error_commandExecutionFailed;
+
+ public static String TabTerminalListener_consoleTerminated;
+
+ 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_localEchoSelectorControl_label;
+
+ public static String OutputStreamMonitor_error_readingFromStream;
+
+ public static String InputStreamMonitor_error_writingToStream;
+
+ public static String ProcessConnector_error_creatingProcess;
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties
new file mode 100644
index 000000000..992eeb80e
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/nls/Messages.properties
@@ -0,0 +1,20 @@
+#
+# org.eclipse.tm.te.ui.terminals
+# Externalized Strings.
+#
+
+AbstractAction_error_commandExecutionFailed="Failed to execute command (id = {0}). Possibly caused by: {1}
+
+TabTerminalListener_consoleTerminated=<terminated> {0}
+
+ProcessSettingsPage_dialogTitle=Select Process Image
+ProcessSettingsPage_processImagePathSelectorControl_label=Image Path:
+ProcessSettingsPage_processImagePathSelectorControl_button=Browse
+ProcessSettingsPage_processArgumentsControl_label=Arguments:
+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}
+
+ProcessConnector_error_creatingProcess=Exception when creating process. Possibly caused by: {0}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java
new file mode 100644
index 000000000..84f9df3c0
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessConnector.java
@@ -0,0 +1,425 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.process;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+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.IPath;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.osgi.service.environment.Constants;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage;
+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.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.nls.Messages;
+import org.eclipse.tm.te.ui.terminals.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 <code>null</code>
+ */
+ public ProcessConnector(ProcessSettings settings) {
+ super();
+
+ Assert.isNotNull(settings);
+ this.settings = settings;
+ }
+
+ /**
+ * Returns the process object or <code>null</code> if the
+ * connector is connector.
+ *
+ * @return The process object or <code>null</code>.
+ */
+ 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 control != null;
+ super.connect(control);
+
+ pty = null;
+ width = -1;
+ height = -1;
+
+ try {
+ // 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()) {
+ try {
+ pty = new PTY(false);
+ } catch (IOException e) {
+ // PTY not supported on windows
+ }
+ }
+
+ // 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());
+ }
+
+ 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<String> argv = new ArrayList<String>();
+ 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()]), getProcessEnvironment(), null, pty);
+ } else {
+ // No PTY -> just execute via the standard Java Runtime implementation.
+ process = Runtime.getRuntime().exec(command.toString());
+ }
+ }
+
+ // connect the streams
+ connectStreams(control, process.getOutputStream(), process.getInputStream(), (pty == null ? process.getErrorStream() : null));
+
+ // Set the terminal control state to CONNECTED
+ control.setState(TerminalState.CONNECTED);
+
+ // Create the process monitor
+ monitor = new ProcessMonitor(this);
+ monitor.startMonitoring();
+ } catch (Exception e) {
+ IStatus status = new Status(IStatus.ERROR, UIPlugin.getUniqueIdentifier(),
+ NLS.bind(Messages.ProcessConnector_error_creatingProcess, e.getLocalizedMessage()), e);
+ UIPlugin.getDefault().getLog().log(status);
+ }
+ }
+
+ /* (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.internal.terminal.provisional.api.provider.TerminalConnectorImpl#doDisconnect()
+ */
+ @Override
+ public void doDisconnect() {
+ // Dispose the process
+ if (process != null) { process.destroy(); process = null; }
+
+ // 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#makeSettingsPage()
+ */
+ @Override
+ public ISettingsPage makeSettingsPage() {
+ return new ProcessSettingsPage(settings);
+ }
+
+ /* (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);
+ }
+ }
+ }
+
+ // ***** Process Environment Handling *****
+
+ // 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 once retrieved
+ private static Map<String, String> nativeEnvironment = null;
+ // Reference to the native environment with the case of the variable names preserved
+ private static Map<String, String> nativeEnvironmentCasePreserved = null;
+
+ /**
+ * Returns the specific environment to set for the process to be launched.
+ *
+ * @return The process environment.
+ */
+ private static String[] getProcessEnvironment() {
+ Map<String, String> env = getNativeEnvironment();
+
+ env.put("TERM", "vt100"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Iterator<Map.Entry<String, String>> iter = env.entrySet().iterator();
+ List<String> strings = new ArrayList<String>(env.size());
+ StringBuffer buffer = null;
+ while (iter.hasNext()) {
+ Map.Entry<String, String>entry = iter.next();
+ buffer = new StringBuffer(entry.getKey());
+ buffer.append('=').append(entry.getValue());
+ strings.add(buffer.toString());
+ }
+
+ return strings.toArray(new String[strings.size()]);
+ }
+
+ /**
+ * Determine the native environment, but returns all environment variable
+ * names in upper case.
+ *
+ * @return The native environment with upper case variable names, or an empty map.
+ */
+ private static Map<String, String> getNativeEnvironment() {
+ synchronized (ENV_GET_MONITOR) {
+ if (nativeEnvironment == null) {
+ Map<String, String> casePreserved = getNativeEnvironmentCasePreserved();
+ if (Platform.getOS().equals(org.eclipse.osgi.service.environment.Constants.OS_WIN32)) {
+ nativeEnvironment = new HashMap<String, String>();
+ Iterator<Map.Entry<String, String>> entries = casePreserved.entrySet().iterator();
+ while (entries.hasNext()) {
+ Map.Entry<String, String> entry = entries.next();
+ nativeEnvironment.put(entry.getKey().toUpperCase(), entry.getValue());
+ }
+ } else {
+ nativeEnvironment = new HashMap<String, String>(casePreserved);
+ }
+ }
+ return new HashMap<String, String>(nativeEnvironment);
+ }
+ }
+
+ /**
+ * Determine the native environment.
+ *
+ * @return The native environment, or an empty map.
+ */
+ private static Map<String, String> getNativeEnvironmentCasePreserved() {
+ synchronized (ENV_GET_MONITOR) {
+ if (nativeEnvironmentCasePreserved == null) {
+ nativeEnvironmentCasePreserved= new HashMap<String, String>();
+ cacheNativeEnvironment(nativeEnvironmentCasePreserved);
+ }
+ return new HashMap<String, String>(nativeEnvironmentCasePreserved);
+ }
+ }
+
+ /**
+ * Query the native environment and store it to the specified cache.
+ *
+ * @param cache The environment cache. Must not be <code>null</code>.
+ */
+ private static void cacheNativeEnvironment(Map<String, String> cache) {
+ Assert.isNotNull(cache);
+
+ try {
+ String nativeCommand = null;
+ boolean isWin9xME = false; // see bug 50567
+ String fileName = null;
+ if (Platform.getOS().equals(Constants.OS_WIN32)) {
+ String osName = System.getProperty("os.name"); //$NON-NLS-1$
+ isWin9xME = osName != null && (osName.startsWith("Windows 9") || osName.startsWith("Windows ME")); //$NON-NLS-1$ //$NON-NLS-2$
+ if (isWin9xME) {
+ // Win 95, 98, and ME
+ // SET might not return therefore we pipe into a file
+ IPath stateLocation = UIPlugin.getDefault().getStateLocation();
+ fileName = stateLocation.toOSString() + File.separator + "env.txt"; //$NON-NLS-1$
+ nativeCommand = "command.com /C set > " + fileName; //$NON-NLS-1$
+ } else {
+ // Win NT, 2K, XP
+ 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);
+ if (isWin9xME) {
+ // read piped data on Win 95, 98, and ME
+ Properties p = new Properties();
+ File file = new File(fileName);
+ InputStream stream = new BufferedInputStream(new FileInputStream(file));
+ p.load(stream);
+ stream.close();
+ if (!file.delete()) {
+ file.deleteOnExit(); // if delete() fails try again on VM close
+ }
+ for (Enumeration<Object> enumeration = p.keys(); enumeration.hasMoreElements();) {
+ // Win32's environment variables are case insensitive. Put everything
+ // to upper case so that (for example) the "PATH" variable will match
+ // "pAtH" correctly on Windows.
+ String key = (String)enumeration.nextElement();
+ cache.put(key, (String)p.get(key));
+ }
+ } else {
+ // 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);
+ String line = reader.readLine();
+ String key = null;
+ String value = null;
+ while (line != 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);
+ while (line != null && !line.equals("}")) { //$NON-NLS-1$
+ line = reader.readLine();
+ if (line != null) {
+ value += line;
+ }
+ }
+ line = reader.readLine();
+ } else {
+ int separator = line.indexOf('=');
+ if (separator > 0) {
+ key = line.substring(0, separator);
+ value = line.substring(separator + 1);
+ 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) {
+ value += 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('=');
+ }
+ }
+ }
+ }
+ if (key != null) {
+ cache.put(key, value);
+ key = null;
+ value = null;
+ } else {
+ line = reader.readLine();
+ }
+ }
+ reader.close();
+ }
+ } catch (IOException e) {
+ // Native environment-fetching code failed.
+ // This can easily happen and is not useful to log.
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java
new file mode 100644
index 000000000..98c9d6073
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessMonitor.java
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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 <code>null</code>.
+ */
+ 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.
+ */
+ @SuppressWarnings("restriction")
+ 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
+ processConnector.disconnect();
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java
new file mode 100644
index 000000000..5976fdfed
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettings.java
@@ -0,0 +1,162 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.te.runtime.interfaces.properties.IPropertiesContainer;
+
+/**
+ * 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();
+
+ /**
+ * Sets the process image.
+ *
+ * @param image The process image or <code>null</code>.
+ */
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ /**
+ * Returns the process image.
+ *
+ * @return The process image or <code>null</code>.
+ */
+ public String getImage() {
+ return image;
+ }
+
+ /**
+ * Sets the process arguments.
+ * <p>
+ * The arguments are space separated. The caller is responsible for
+ * correct quoting.
+ *
+ * @param arguments The process arguments or <code>null</code>.
+ */
+ public void setArguments(String arguments) {
+ this.arguments = arguments;
+ }
+
+ /**
+ * Returns the process arguments.
+ *
+ * @return The process arguments as space separated list or <code>null</code>.
+ */
+ public String getArguments() {
+ return arguments;
+ }
+
+ /**
+ * Sets the process object.
+ *
+ * @param image The process object or <code>null</code>.
+ */
+ public void setProcess(Process process) {
+ this.process = process;
+ }
+
+ /**
+ * Returns the process object.
+ *
+ * @return The process object or <code>null</code>.
+ */
+ public Process getProcess() {
+ return process;
+ }
+
+ /**
+ * Sets the pseudo terminal object.
+ *
+ * @param pty The pseudo terminal or <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ public PTY getPTY() {
+ return pty;
+ }
+
+ /**
+ * Sets if the process requires a local echo from the
+ * terminal widget.
+ *
+ * @param value Specify <code>true</code> to enable the local echo, <code>false</code> otherwise.
+ */
+ public void setLocalEcho(boolean value) {
+ this.localEcho = value;
+ }
+
+ /**
+ * Returns <code>true</code> if the process requires a local echo
+ * from the terminal widget.
+ *
+ * @return <code>True</code> if local echo is enabled, <code>false</code> otherwise.
+ */
+ public boolean isLocalEcho() {
+ return localEcho;
+ }
+
+ /**
+ * Loads the process settings from the given settings store.
+ *
+ * @param store The settings store. Must not be <code>null</code>.
+ */
+ 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$
+ if (store instanceof IPropertiesContainer) {
+ process = (Process)((IPropertiesContainer)store).getProperty("Process"); //$NON-NLS-1$
+ pty = (PTY)((IPropertiesContainer)store).getProperty("PTY"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Saves the process settings to the given settings store.
+ *
+ * @param store The settings store. Must not be <code>null</code>.
+ */
+ 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$
+ if (store instanceof IPropertiesContainer) {
+ ((IPropertiesContainer)store).setProperty("Process", process); //$NON-NLS-1$
+ ((IPropertiesContainer)store).setProperty("PTY", pty); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java
new file mode 100644
index 000000000..af7a4e60b
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/process/ProcessSettingsPage.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.ISettingsPage;
+import org.eclipse.tm.te.ui.swt.SWTControlUtil;
+import org.eclipse.tm.te.ui.terminals.nls.Messages;
+import org.eclipse.ui.PlatformUI;
+import org.osgi.framework.Bundle;
+
+/**
+ * Process connector settings page implementation.
+ */
+@SuppressWarnings("restriction")
+public class ProcessSettingsPage implements ISettingsPage {
+ private Text processImageSelectorControl;
+ private Button processImageSelectorControlButton;
+ private Text processArgumentsControl;
+ private Button localEchoSelectorControl;
+
+ 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 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 <code>null</code>.
+ */
+ 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 = SWTControlUtil.getText(processImageSelectorControl);
+ 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.RESOLVED || bundle.getState() == Bundle.ACTIVE)) {
+ dialog.setFilterPath(org.eclipse.core.resources.ResourcesPlugin.getWorkspace().getRoot().getLocation().toOSString());
+ }
+ }
+
+ // Open the dialog
+ selectedFile = dialog.open();
+ if (selectedFile != null) {
+ SWTControlUtil.setText(processImageSelectorControl, selectedFile);
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#saveSettings()
+ */
+ @Override
+ public void saveSettings() {
+ settings.setImage(SWTControlUtil.getText(processImageSelectorControl));
+ settings.setArguments(SWTControlUtil.getText(processArgumentsControl));
+ settings.setLocalEcho(SWTControlUtil.getSelection(localEchoSelectorControl));
+ settings.setProcess(null);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.internal.terminal.provisional.api.ISettingsPage#loadSettings()
+ */
+ @Override
+ public void loadSettings() {
+ SWTControlUtil.setText(processImageSelectorControl, settings.getImage());
+ SWTControlUtil.setText(processArgumentsControl, settings.getArguments());
+ SWTControlUtil.setSelection(localEchoSelectorControl, settings.isLocalEcho());
+ }
+
+ /* (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 = SWTControlUtil.getText(processImageSelectorControl);
+ return selectedFile != null && !"".equals(selectedFile.trim()) && new Path(selectedFile).toFile().canRead(); //$NON-NLS-1$
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java
new file mode 100644
index 000000000..18e14fcfc
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/AbstractStreamsConnector.java
@@ -0,0 +1,128 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.streams;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl;
+import org.eclipse.tm.internal.terminal.provisional.api.provider.TerminalConnectorImpl;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Streams connector implementation.
+ */
+@SuppressWarnings("restriction")
+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;
+
+ /**
+ * 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 <code>null</code>.
+ * @param stdin The stdin stream or <code>null</code>.
+ * @param stdout The stdout stream or <code>null</code>.
+ * @param stderr The stderr stream or <code>null</code>.
+ */
+ protected void connectStreams(ITerminalControl terminalControl, OutputStream stdin, InputStream stdout, InputStream stderr) {
+ assert terminalControl != null;
+
+ // Create the input stream monitor
+ if (stdin != null) {
+ stdInMonitor = createStdInMonitor(terminalControl, stdin);
+ // 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);
+ // Register the connector if it implements IDisposable
+ if (this instanceof IDisposable) stdOutMonitor.addDisposable((IDisposable)this);
+ // Start the monitoring
+ stdOutMonitor.startMonitoring();
+ }
+
+ // Create the error stream monitor
+ if (stderr != null) {
+ stdErrMonitor = createStdErrMonitor(terminalControl, stderr);
+ // Register the connector if it implements IDisposable and stdout is not monitored
+ if (stdout == null && this instanceof IDisposable) stdErrMonitor.addDisposable((IDisposable)this);
+ // 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 <code>null</code>.
+ * @param stdin The stdin stream or <code>null</code>.
+ * @return input stream monitor
+ */
+ protected InputStreamMonitor createStdInMonitor(ITerminalControl terminalControl, OutputStream stdin) {
+ return new InputStreamMonitor(terminalControl, stdin);
+ }
+
+ /**
+ * 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 <code>null</code>.
+ * @param stdout The stdout stream or <code>null</code>.
+ * @return output stream monitor
+ */
+ protected OutputStreamMonitor createStdOutMonitor(ITerminalControl terminalControl, InputStream stdout) {
+ return new OutputStreamMonitor(terminalControl, stdout);
+ }
+
+ /**
+ * 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 <code>null</code>.
+ * @param stderr The stderr stream or <code>null</code>.
+ * @return output stream monitor
+ */
+ protected OutputStreamMonitor createStdErrMonitor(ITerminalControl terminalControl, InputStream stderr) {
+ return new OutputStreamMonitor(terminalControl, stderr);
+ }
+
+ /* (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/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java
new file mode 100644
index 000000000..d47c53319
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/InputStreamMonitor.java
@@ -0,0 +1,215 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.nls.Messages;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Input stream monitor implementation.
+ * <p>
+ * <b>Note:</b> The input is coming <i>from</i> the terminal. Therefore, the input
+ * stream monitor is attached to the stdin stream of the monitored (remote) process.
+ */
+@SuppressWarnings("restriction")
+public class InputStreamMonitor extends OutputStream implements IDisposable {
+ // Reference to the parent terminal control
+ @SuppressWarnings("unused")
+ private final ITerminalControl terminalControl;
+
+ // Reference to the monitored (output) stream
+ private final OutputStream stream;
+
+ // Reference to the thread writing the stream
+ private Thread thread;
+
+ // Flag to mark the monitor disposed. When disposed,
+ // no further data is written from the monitored stream.
+ private boolean disposed;
+
+ // A list of object to dispose if this monitor is disposed
+ private final List<IDisposable> disposables = new ArrayList<IDisposable>();
+
+ // Queue to buffer the data to write to the output stream
+ private final Queue<byte[]> queue = new LinkedList<byte[]>();
+
+ /**
+ * Constructor.
+ *
+ * @param terminalControl The parent terminal control. Must not be <code>null</code>.
+ * @param stream The stream. Must not be <code>null</code>.
+ */
+ public InputStreamMonitor(ITerminalControl terminalControl, OutputStream stream) {
+ super();
+
+ Assert.isNotNull(terminalControl);
+ this.terminalControl = terminalControl;
+ Assert.isNotNull(stream);
+ this.stream = stream;
+ }
+
+ /**
+ * 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 <code>null</code>.
+ */
+ public final void addDisposable(IDisposable disposable) {
+ assert disposable != null;
+ if (!disposed && !disposables.contains(disposable)) disposables.add(disposable);
+ }
+
+ /**
+ * Removes the disposable object from the list.
+ *
+ * @param disposable The disposable object. Must not be <code>null</code>.
+ */
+ public final void removeDisposable(IDisposable disposable) {
+ assert disposable != null;
+ 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
+ while (thread != null && !disposed) {
+ // If the queue is empty, wait until notified
+ if (queue.isEmpty()) {
+ synchronized(queue) {
+ try { queue.wait(); } catch (InterruptedException e) { /* ignored on purpose */ }
+ }
+ }
+
+ // If the queue is not empty, take the first element
+ // and write the data to the stream
+ while (!queue.isEmpty() && !disposed) {
+ // Retrieves the queue head (is null if queue is empty (should never happen))
+ byte[] data = queue.poll();
+ if (data != null) {
+ try {
+ // Write the data to the stream
+ stream.write(data);
+ // Flush the stream immediately
+ stream.flush();
+ } 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);
+ }
+ }
+ }
+ }
+ }
+
+ // 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();
+ }
+ }
+
+ @Override
+ public void write(byte[] b, int off, int len) throws IOException {
+ // Make sure that the written block is not interlaced with other input.
+ synchronized(queue) {
+ super.write(b, off, len);
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java
new file mode 100644
index 000000000..ea8ab62fc
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/OutputStreamMonitor.java
@@ -0,0 +1,222 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.Status;
+import org.eclipse.osgi.util.NLS;
+import org.eclipse.tm.internal.terminal.provisional.api.ITerminalControl;
+import org.eclipse.tm.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.nls.Messages;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Output stream monitor implementation.
+ * <p>
+ * <b>Note:</b> The output is going <i>to</i> the terminal. Therefore, the output
+ * stream monitor is attached to the stdout and/or stderr stream of the monitored
+ * (remote) process.
+ */
+@SuppressWarnings("restriction")
+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;
+
+ // 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<IDisposable> disposables = new ArrayList<IDisposable>();
+
+ /**
+ * Constructor.
+ *
+ * @param terminalControl The parent terminal control. Must not be <code>null</code>.
+ * @param stream The stream. Must not be <code>null</code>.
+ */
+ public OutputStreamMonitor(ITerminalControl terminalControl, InputStream stream) {
+ super();
+
+ Assert.isNotNull(terminalControl);
+ this.terminalControl = terminalControl;
+ Assert.isNotNull(stream);
+ this.stream = new BufferedInputStream(stream, BUFFER_SIZE);
+ }
+
+ /**
+ * 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 <code>null</code>.
+ */
+ public final void addDisposable(IDisposable disposable) {
+ assert disposable != null;
+ if (!disposed && !disposables.contains(disposable)) disposables.add(disposable);
+ }
+
+ /**
+ * Removes the disposable object from the list.
+ *
+ * @param disposable The disposable object. Must not be <code>null</code>.
+ */
+ public final void removeDisposable(IDisposable disposable) {
+ assert disposable != null;
+ 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.
+ * <p>
+ * The default implementation is returning the byte stream unmodified.
+ *
+ * @param byteBuffer The byte stream. Must not be <code>null</code>.
+ * @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 byteBuffer != null;
+ return byteBuffer;
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java
new file mode 100644
index 000000000..0bc89e64c
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsConnector.java
@@ -0,0 +1,113 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.TerminalState;
+import org.eclipse.ui.services.IDisposable;
+
+/**
+ * Streams connector implementation.
+ */
+@SuppressWarnings("restriction")
+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 <code>null</code>
+ */
+ 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);
+
+ // connect the streams
+ connectStreams(control, settings.getStdinStream(), settings.getStdoutStream(), settings.getStderrStream());
+
+ // 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.internal.terminal.provisional.api.provider.TerminalConnectorImpl#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$
+ }
+
+ /* (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/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java
new file mode 100644
index 000000000..a3ef45196
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/streams/StreamsSettings.java
@@ -0,0 +1,135 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.te.runtime.interfaces.properties.IPropertiesContainer;
+
+/**
+ * Streams connector settings implementation.
+ */
+@SuppressWarnings("restriction")
+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;
+
+ /**
+ * Sets the stdin stream instance.
+ *
+ * @param stdin The stream instance or <code>null</code>.
+ */
+ public void setStdinStream(OutputStream stdin) {
+ this.stdin = stdin;
+ }
+
+ /**
+ * Returns the stdin stream instance.
+ *
+ * @return The stream instance or <code>null</code>.
+ */
+ public OutputStream getStdinStream() {
+ return stdin;
+ }
+
+ /**
+ * Sets the stdout stream instance.
+ *
+ * @param stdout The stream instance or <code>null</code>.
+ */
+ public void setStdoutStream(InputStream stdout) {
+ this.stdout = stdout;
+ }
+
+ /**
+ * Returns the stdout stream instance.
+ *
+ * @return The stream instance or <code>null</code>.
+ */
+ public InputStream getStdoutStream() {
+ return stdout;
+ }
+
+ /**
+ * Sets the stderr stream instance.
+ *
+ * @param stderr The stream instance or <code>null</code>.
+ */
+ public void setStderrStream(InputStream stderr) {
+ this.stderr = stderr;
+ }
+
+ /**
+ * Returns the stderr stream instance.
+ *
+ * @return The stream instance or <code>null</code>.
+ */
+ public InputStream getStderrStream() {
+ return stderr;
+ }
+
+ /**
+ * Sets if the process requires a local echo from the terminal widget.
+ *
+ * @param value Specify <code>true</code> to enable the local echo, <code>false</code> otherwise.
+ */
+ public void setLocalEcho(boolean value) {
+ this.localEcho = value;
+ }
+
+ /**
+ * Returns <code>true</code> if the process requires a local echo
+ * from the terminal widget.
+ *
+ * @return <code>True</code> if local echo is enabled, <code>false</code> otherwise.
+ */
+ public boolean isLocalEcho() {
+ return localEcho;
+ }
+
+ /**
+ * Loads the streams settings from the given settings store.
+ *
+ * @param store The settings store. Must not be <code>null</code>.
+ */
+ public void load(ISettingsStore store) {
+ Assert.isNotNull(store);
+ localEcho = Boolean.parseBoolean(store.get("LocalEcho", Boolean.FALSE.toString())); //$NON-NLS-1$
+ if (store instanceof IPropertiesContainer) {
+ stdin = (OutputStream)((IPropertiesContainer)store).getProperty("stdin"); //$NON-NLS-1$
+ stdout = (InputStream)((IPropertiesContainer)store).getProperty("stdout"); //$NON-NLS-1$
+ stderr = (InputStream)((IPropertiesContainer)store).getProperty("stderr"); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Saves the process settings to the given settings store.
+ *
+ * @param store The settings store. Must not be <code>null</code>.
+ */
+ public void save(ISettingsStore store) {
+ Assert.isNotNull(store);
+ store.put("LocalEcho", Boolean.toString(localEcho)); //$NON-NLS-1$
+ if (store instanceof IPropertiesContainer) {
+ ((IPropertiesContainer)store).setProperty("stdin", stdin); //$NON-NLS-1$
+ ((IPropertiesContainer)store).setProperty("stdout", stdout); //$NON-NLS-1$
+ ((IPropertiesContainer)store).setProperty("stderr", stderr); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java
new file mode 100644
index 000000000..09f7783a8
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabDisposeListener.java
@@ -0,0 +1,67 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.tm.internal.terminal.control.ITerminalViewControl;
+import org.eclipse.tm.te.runtime.events.DisposedEvent;
+import org.eclipse.tm.te.runtime.events.EventManager;
+
+/**
+ * Terminals tab default dispose listener implementation.
+ */
+@SuppressWarnings("restriction")
+public class TabDisposeListener implements DisposeListener {
+ private final TabFolderManager parentTabFolderManager;
+
+ /**
+ * Constructor.
+ *
+ * @param parentTabFolderManager The parent tab folder manager. Must be not <code>null</code>
+ */
+ 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)candidate).disposeTerminal();
+
+ // 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
+ EventManager.getInstance().fireEvent(new DisposedEvent(e.getSource(), ((CTabItem)e.getSource()).getData("customData"))); //$NON-NLS-1$
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java
new file mode 100644
index 000000000..491548ec4
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderManager.java
@@ -0,0 +1,720 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.tabs;
+
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.EventObject;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+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.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.events.DisposeEvent;
+import org.eclipse.swt.events.DisposeListener;
+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.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.TerminalState;
+import org.eclipse.tm.te.runtime.events.EventManager;
+import org.eclipse.tm.te.ui.events.AbstractEventListener;
+import org.eclipse.tm.te.ui.swt.DisplayUtil;
+import org.eclipse.tm.te.ui.terminals.activator.UIPlugin;
+import org.eclipse.tm.te.ui.terminals.events.SelectionChangedBroadcastEvent;
+import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView;
+import org.eclipse.tm.te.ui.terminals.interfaces.ImageConsts;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.ide.IDEEncoding;
+
+/**
+ * Terminals tab folder manager.
+ */
+@SuppressWarnings("restriction")
+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;
+ // Reference to the broadcasted selection changed event listener instance
+ private final BroadcastedSelectionChangedEventListener broadcastedSelectionChangedEventListener;
+
+ /**
+ * List of selection changed listeners.
+ */
+ private final List<ISelectionChangedListener> selectionChangedListeners = new ArrayList<ISelectionChangedListener>();
+
+ /**
+ * 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 be not <code>null</code>.
+ */
+ 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
+ DisplayUtil.safeAsyncExec(new Runnable() {
+ @Override
+ public void run() {
+ fireSelectionChanged(new StructuredSelection(getTerminal().getSelection()));
+ }
+ });
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.swt.events.MouseListener#mouseDoubleClick(org.eclipse.swt.events.MouseEvent)
+ */
+ @Override
+ public void mouseDoubleClick(MouseEvent e) {
+ }
+ }
+
+ /**
+ * The event listener to process broadcasted selection changed events
+ */
+ private class BroadcastedSelectionChangedEventListener extends AbstractEventListener {
+ private final TabFolderManager parent;
+
+ /**
+ * Constructor.
+ *
+ * @param parent The parent tab folder manager. Must not be <code>null</code>.
+ */
+ public BroadcastedSelectionChangedEventListener(TabFolderManager parent) {
+ super();
+
+ Assert.isNotNull(parent);
+ this.parent = parent;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.runtime.interfaces.events.IEventListener#eventFired(java.util.EventObject)
+ */
+ @Override
+ public void eventFired(EventObject event) {
+ if (event instanceof SelectionChangedBroadcastEvent && !event.getSource().equals(parent)) {
+ // Don't need to do anything if the parent tab folder is disposed or does not have a open tab
+ CTabFolder tabFolder = parent.getTabFolder();
+ if (tabFolder == null || tabFolder.isDisposed() || tabFolder.getItemCount() == 0) return;
+
+ // Received a broadcasted selection changed event from another tab folder manager.
+ SelectionChangedEvent selectionChangedEvent = ((SelectionChangedBroadcastEvent)event).getSelectionChangedEvent();
+ if (selectionChangedEvent != null && selectionChangedEvent.getSelection() instanceof IStructuredSelection && !selectionChangedEvent.getSelection().isEmpty()) {
+ // Extract the selection from the selection changed event
+ IStructuredSelection selection = (IStructuredSelection)selectionChangedEvent.getSelection();
+ // Determine the first element in the selection being a CTabItem
+ CTabItem item = null;
+ Iterator<?> iterator = selection.iterator();
+ while (iterator.hasNext()) {
+ Object candidate = iterator.next();
+ if (candidate instanceof CTabItem) { item = (CTabItem)candidate; break; }
+ }
+ // If we got an CTabItem from the selection, try to find a CTabItem in our own tab folder manager
+ // which is associated with the exact same data object.
+ if (item != null && item.getData("customData") != null) { //$NON-NLS-1$
+ Object data = item.getData("customData"); //$NON-NLS-1$
+
+ CTabItem[] ourItems = tabFolder.getItems();
+ for (CTabItem ourItem : ourItems) {
+ Object ourData = ourItem.getData("customData"); //$NON-NLS-1$
+ if (data.equals(ourData) && !ourItem.equals(parent.getActiveTabItem())) {
+ // Select this item and we are done
+ parent.setSelection(new StructuredSelection(ourItem));
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parentView The parent terminal console view. Must be not <code>null</code>.
+ */
+ 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);
+
+
+ // Create and register the broadcasted selection changed event listener
+ broadcastedSelectionChangedEventListener = doCreateBroadcastedSelectionChangedEventListener(this);
+ if (isListeningToBroadcastedSelectionChangedEvent() && broadcastedSelectionChangedEventListener != null) {
+ EventManager.getInstance().addEventListener(broadcastedSelectionChangedEventListener, SelectionChangedBroadcastEvent.class);
+ }
+ }
+
+ /**
+ * Creates the terminal console tab folder selection listener instance.
+ *
+ * @param parent The parent terminal console tab folder manager. Must be not <code>null</code>.
+ * @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 <code>null</code>.
+ */
+ 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);
+ // Remove the broadcasted selection changed event listener from the notification manager
+ if (broadcastedSelectionChangedEventListener != null) {
+ EventManager.getInstance().removeEventListener(broadcastedSelectionChangedEventListener);
+ }
+ }
+
+ /**
+ * Creates a new tab item with the given title and connector.
+ *
+ * @param title The tab title. Must be not <code>null</code>.
+ * @param connector The terminal connector. Must be not <code>null</code>.
+ * @param data The custom terminal data node or <code>null</code>.
+ *
+ * @return The created tab item or <code>null</code> if failed.
+ */
+ @SuppressWarnings("unused")
+ public CTabItem createTabItem(String title, ITerminalConnector connector, Object data) {
+ 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(item), composite, new ITerminalConnector[] { connector });
+ // Add the "selection" listener to the terminal control
+ new TerminalControlSelectionListener(terminal);
+ // Use the default Eclipse IDE encoding setting to configure the terminals encoding
+ try { terminal.setEncoding(IDEEncoding.getResourceEncoding()); } 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;
+ }
+
+ /**
+ * Generate a unique title string based on the given proposal.
+ *
+ * @param proposal The proposal. Must be not <code>null</code>.
+ * @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<String> titles = new ArrayList<String>();
+ for (CTabItem item : tabFolder.getItems()) {
+ // Get the tab item title
+ titles.add(item.getText());
+ // Make the proposal unique be appending (<n>) 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 be not <code>null</code>.
+ */
+ protected void setupTerminalTabListeners(CTabItem item) {
+ Assert.isNotNull(item);
+
+ // Create and associate the disposal listener
+ item.addDisposeListener(doCreateTerminalTabDisposeListener(this));
+
+ // Create and register the property change listener
+ final IPropertyChangeListener propertyChangeListener = doCreateTerminalTabPropertyChangeListener(item);
+ // Register to the JFace font registry
+ JFaceResources.getFontRegistry().addListener(propertyChangeListener);
+ // Remove the listener from the JFace font registry if the tab gets disposed
+ item.addDisposeListener(new DisposeListener() {
+ @Override
+ public void widgetDisposed(DisposeEvent e) {
+ JFaceResources.getFontRegistry().removeListener(propertyChangeListener);
+ }
+ });
+ }
+
+ /**
+ * Creates a new terminal console tab terminal listener instance.
+ *
+ * @param item The tab item. Must be not <code>null</code>.
+ * @return The terminal listener instance.
+ */
+ protected ITerminalListener doCreateTerminalTabTerminalListener(CTabItem item) {
+ Assert.isNotNull(item);
+ return new TabTerminalListener(item);
+ }
+
+ /**
+ * Creates a new terminal console tab dispose listener instance.
+ *
+ * @param parent The parent terminal console tab folder manager. Must be not <code>null</code>.
+ * @return The dispose listener instance.
+ */
+ protected DisposeListener doCreateTerminalTabDisposeListener(TabFolderManager parent) {
+ Assert.isNotNull(parent);
+ return new TabDisposeListener(parent);
+ }
+
+ /**
+ * Creates a new terminal console tab property change listener instance.
+ *
+ * @param item The tab item. Must be not <code>null</code>.
+ * @return The property change listener instance.
+ */
+ protected IPropertyChangeListener doCreateTerminalTabPropertyChangeListener(CTabItem item) {
+ Assert.isNotNull(item);
+ return new TabPropertyChangeListener(item);
+ }
+
+ /**
+ * Returns the tab item image.
+ *
+ * @param connector The terminal connector. Must be not <code>null</code>.
+ * @param data The custom terminal data node or <code>null</code>.
+ *
+ * @return The tab item image or <code>null</code>.
+ */
+ 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.
+ * <p>
+ * <b>Note:</b> The method will handle unified tab item titles itself.
+ *
+ * @param title The tab item title. Must be not <code>null</code>.
+ * @param connector The terminal connector. Must be not <code>null</code>.
+ * @param data The custom terminal data node or <code>null</code>.
+ *
+ * @return The corresponding tab item or <code>null</code>.
+ */
+ 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 be not <code>null</code>.
+ */
+ 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 <code>null</code> 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 <code>null</code>.
+ * @return <code>True</code> if the tab item represents a terminated console, <code>false</code> 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 "<terminated>", the item can be removed
+ String itemTitle = item.getText();
+ if (itemTitle != null && itemTitle.contains("<terminated>")) { //$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;
+ }
+
+ /* (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() {
+ fireSelectionChanged(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);
+ }
+
+ // Second, broadcast the event if desired
+ if (isBroadcastSelectionChangedEvent()) onBroadcastSelectionChangedEvent(event);
+ }
+
+ /**
+ * Controls if or if not a selection changed event, processed by this tab
+ * folder manager shall be broadcasted to via the global Workbench notification
+ * mechanism.
+ *
+ * @return <code>True</code> to broadcast the selection changed event, <code>false</code> otherwise.
+ */
+ protected boolean isBroadcastSelectionChangedEvent() {
+ return false;
+ }
+
+ /**
+ * Broadcasts the given selection changed event via the global Workbench notification mechanism.
+ *
+ * @param selectionChangedEvent The selection changed event or <code>null</code>.
+ */
+ protected void onBroadcastSelectionChangedEvent(SelectionChangedEvent selectionChangedEvent) {
+ SelectionChangedBroadcastEvent event = doCreateSelectionChangedBroadcastEvent(this, selectionChangedEvent);
+ if (event != null) EventManager.getInstance().fireEvent(event);
+ }
+
+ /**
+ * Creates the selection changed broadcast event.
+ *
+ * @param source The event source. Must not be <code>null</code>.
+ * @param selectionChangedEvent The selection changed event or <code>null</code>.
+ *
+ * @return The selection changed broadcast event or <code>null</code>.
+ */
+ protected SelectionChangedBroadcastEvent doCreateSelectionChangedBroadcastEvent(TabFolderManager source, SelectionChangedEvent selectionChangedEvent) {
+ return new SelectionChangedBroadcastEvent(source, selectionChangedEvent);
+ }
+
+ /**
+ * Returns if or if not this tab folder manager is listening to broadcasted selection
+ * changed events. Broadcasted events by the same tab folder manager are ignored independent
+ * of the methods return value.
+ *
+ * @return <code>True</code> to listen to broadcasted selection changed events, <code>false</code> to not listen.
+ */
+ protected boolean isListeningToBroadcastedSelectionChangedEvent() {
+ return false;
+ }
+
+ /**
+ * Creates a new broadcasted selection changed event listener instance.
+ *
+ * @param parent The parent tab folder manager. Must not be <code>null</code>.
+ * @return The event listener instance or <code>null</code>.
+ */
+ protected BroadcastedSelectionChangedEventListener doCreateBroadcastedSelectionChangedEventListener(TabFolderManager parent) {
+ return new BroadcastedSelectionChangedEventListener(parent);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java
new file mode 100644
index 000000000..91d6fb19a
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderMenuHandler.java
@@ -0,0 +1,297 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.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.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.te.ui.terminals.actions.TabScrollLockAction;
+import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView;
+import org.eclipse.ui.IWorkbenchActionConstants;
+
+/**
+ * Terminals tab folder menu handler.
+ */
+@SuppressWarnings("restriction")
+public class TabFolderMenuHandler extends PlatformObject {
+ // Reference to the parent terminal 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<AbstractTerminalAction> contextMenuActions = new ArrayList<AbstractTerminalAction>();
+
+ /**
+ * 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) {
+ updateMenuItems(true);
+ }
+
+ }
+
+ /**
+ * Constructor.
+ *
+ * @param parentView The parent terminal console view. Must not be <code>null</code>.
+ */
+ public TabFolderMenuHandler(ITerminalsView parentView) {
+ super();
+ Assert.isNotNull(parentView);
+ this.parentView = parentView;
+ }
+
+ /**
+ * Returns the parent terminal console view.
+ *
+ * @return The parent terminal console view instance.
+ */
+ protected final ITerminalsView getParentView() {
+ return parentView;
+ }
+
+ /**
+ * Returns the tab folder associated with the parent view.
+ *
+ * @return The tab folder or <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ 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$
+ // Create and associated the menu listener
+ contextMenuManager.addMenuListener(new MenuListener());
+ // Create the context menu
+ contextMenu = contextMenuManager.createContextMenu(tabFolder);
+
+ // 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());
+ }
+
+ /**
+ * Adds the given action to the context menu actions list.
+ *
+ * @param action The action instance. Must be not <code>null</code>.
+ */
+ protected final void add(AbstractTerminalAction action) {
+ Assert.isNotNull(action);
+ contextMenuActions.add(action);
+ }
+
+ /**
+ * Create the context menu actions.
+ */
+ 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() {
+ /* (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();
+ }
+ });
+
+ // 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 scroll lock action
+ add (new TabScrollLockAction() {
+ /* (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 <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ protected void doFillContextMenu(MenuManager manager) {
+ assert manager != null;
+
+ // 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 <code>True</code> if the menu is about to show, <code>false</code> 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)
+ */
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (MenuManager.class.isAssignableFrom(adapter)) {
+ return contextMenuManager;
+ } else if (Menu.class.isAssignableFrom(adapter)) {
+ return contextMenu;
+ }
+
+ // Try the parent view
+ Object adapted = getParentView().getAdapter(adapter);
+ if (adapted != null) {
+ return adapted;
+ }
+
+ return super.getAdapter(adapter);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java
new file mode 100644
index 000000000..de25ec3ea
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderSelectionListener.java
@@ -0,0 +1,55 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.tabs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
+
+/**
+ * Terminals tab folder default selection listener implementation.
+ */
+public class TabFolderSelectionListener implements SelectionListener {
+ private final TabFolderManager parentTabFolderManager;
+
+ /**
+ * Constructor.
+ *
+ * @param parentTabFolderManager The parent tab folder manager. Must be not <code>null</code>
+ */
+ 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/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java
new file mode 100644
index 000000000..4215771c9
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabFolderToolbarHandler.java
@@ -0,0 +1,304 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.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.te.ui.terminals.actions.AbstractAction;
+import org.eclipse.tm.te.ui.terminals.actions.TabScrollLockAction;
+import org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView;
+import org.eclipse.ui.IActionBars;
+import org.eclipse.ui.IWorkbenchActionConstants;
+
+
+/**
+ * Terminals tab folder toolbar handler.
+ */
+@SuppressWarnings("restriction")
+public class TabFolderToolbarHandler extends PlatformObject {
+ // Reference to the parent terminal 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<AbstractTerminalAction> toolbarActions = new ArrayList<AbstractTerminalAction>();
+
+ /**
+ * 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 terminal console view. Must not be <code>null</code>.
+ */
+ public TabFolderToolbarHandler(ITerminalsView parentView) {
+ super();
+ Assert.isNotNull(parentView);
+ this.parentView = parentView;
+ }
+
+ /**
+ * Returns the parent terminal console view.
+ *
+ * @return The terminal console view instance.
+ */
+ protected final ITerminalsView getParentView() {
+ return parentView;
+ }
+
+ /**
+ * Returns the tab folder associated with the parent view.
+ *
+ * @return The tab folder or <code>null</code>.
+ */
+ protected final CTabFolder getTabFolder() {
+ return (CTabFolder)getParentView().getAdapter(CTabFolder.class);
+ }
+
+ /**
+ * Returns the currently active terminal control.
+ *
+ * @return The currently active terminal control or <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ 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 selectionChangedListener != null;
+ 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 be not <code>null</code>.
+ */
+ protected final void add(AbstractTerminalAction action) {
+ Assert.isNotNull(action);
+ toolbarActions.add(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();
+ }
+ });
+ }
+
+ /**
+ * Fill in the context menu content within the given manager.
+ *
+ * @param manager The menu manager. Must not be <code>null</code>.
+ */
+ protected void doFillToolbar(IToolBarManager manager) {
+ assert manager != null;
+
+ // 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$
+
+ // 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$
+ }
+ // Add the action itself
+ manager.insertAfter("anchor", action); //$NON-NLS-1$
+ }
+ }
+
+ /**
+ * Update the toolbar items.
+ *
+ * @param enabled <code>True</code> if the items shall be enabled, <code>false</code> 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.setEnabled(false);
+ }
+ else {
+ action.updateAction(enabled);
+ }
+ }
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
+ */
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (IToolBarManager.class.isAssignableFrom(adapter)) {
+ return toolbarManager;
+ }
+ // Try the parent view
+ Object adapted = getParentView().getAdapter(adapter);
+ if (adapted != null) {
+ return adapted;
+ }
+
+ return super.getAdapter(adapter);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java
new file mode 100644
index 000000000..b84b8ee83
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabPropertyChangeListener.java
@@ -0,0 +1,84 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.tabs;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.eclipse.swt.custom.CTabItem;
+import org.eclipse.swt.graphics.Font;
+import org.eclipse.tm.internal.terminal.control.ITerminalViewControl;
+import org.eclipse.tm.internal.terminal.view.TerminalView;
+
+/**
+ * Terminals tab default property change listener implementation.
+ */
+@SuppressWarnings("restriction")
+public class TabPropertyChangeListener implements IPropertyChangeListener {
+ /**
+ * Default terminal font property key.
+ *
+ * @see TerminalView#FONT_DEFINITION
+ */
+ public static final String FONT_DEFINITION = "terminal.views.view.font.definition"; //$NON-NLS-1$
+
+ // Reference to the parent tab item
+ private final CTabItem tabItem;
+
+ /**
+ * Constructor.
+ *
+ * @param tabItem The parent tab item. Must not be <code>null</code>.
+ */
+ public TabPropertyChangeListener(CTabItem tabItem) {
+ super();
+ Assert.isNotNull(tabItem);
+ this.tabItem = tabItem;
+ }
+
+ /**
+ * Returns the associated parent tab item.
+ *
+ * @return The parent tab item.
+ */
+ protected final CTabItem getTabItem() {
+ return tabItem;
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.jface.util.IPropertyChangeListener#propertyChange(org.eclipse.jface.util.PropertyChangeEvent)
+ */
+ @Override
+ public void propertyChange(PropertyChangeEvent event) {
+ // In case we are called once after the tab item got disposed
+ // --> Do nothing
+ if (getTabItem() == null || getTabItem().isDisposed()) return;
+
+ // Listen to changes of the Font settings
+ if (event.getProperty().equals(FONT_DEFINITION)) {
+ onFontDefinitionProperyChanged();
+ }
+ }
+
+ /**
+ * Called if a property change event for the terminal font
+ * definition is received.
+ */
+ protected void onFontDefinitionProperyChanged() {
+ // Get the current font from JFace
+ Font font = JFaceResources.getFont(FONT_DEFINITION);
+ // Get the terminal control from the tab item
+ if (getTabItem().getData() instanceof ITerminalViewControl) {
+ ITerminalViewControl terminal = (ITerminalViewControl)getTabItem().getData();
+ terminal.setFont(font);
+ }
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java
new file mode 100644
index 000000000..4d3824fca
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/tabs/TabTerminalListener.java
@@ -0,0 +1,111 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.tabs;
+
+import java.util.regex.Pattern;
+
+import org.eclipse.core.runtime.Assert;
+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.ITerminalListener;
+import org.eclipse.tm.internal.terminal.provisional.api.TerminalState;
+import org.eclipse.tm.te.ui.terminals.nls.Messages;
+
+/**
+ * Terminals tab default terminal listener implementation.
+ */
+@SuppressWarnings("restriction")
+public class TabTerminalListener implements ITerminalListener {
+ private final CTabItem tabItem;
+
+ /**
+ * Constructor.
+ *
+ * @param tabItem The parent tab item. Must not be <code>null</code>.
+ */
+ public TabTerminalListener(CTabItem tabItem) {
+ super();
+ Assert.isNotNull(tabItem);
+ this.tabItem = tabItem;
+ }
+
+ /**
+ * 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;
+
+ // Update the tab item title
+ item.getDisplay().asyncExec(new Runnable() {
+ @Override
+ public void run() {
+ String newTitle = getTerminalConsoleTabTitle(state);
+ if (newTitle != null) item.setText(newTitle);
+ }
+ });
+ }
+
+ // The pattern will not change over the session life-time
+ private static final Pattern TERMINAL_TITLE_TERMINATED_PATTERN = Pattern.compile(Messages.TabTerminalListener_consoleTerminated.replaceAll("\\{[0-9]+\\}", ".*")); //$NON-NLS-1$ //$NON-NLS-2$
+
+ /**
+ * Returns the title to set to the terminal console tab for the given state.
+ * <p>
+ * <b>Note:</b> This method is called from {@link #setState(TerminalState)} and
+ * is expected to by called within the UI thread.
+ *
+ * @param state The terminal state. Must be not <code>null</code>.
+ * @return The terminal console tab title to set or <code>null</code> to leave the title unchanged.
+ */
+ protected String getTerminalConsoleTabTitle(TerminalState state) {
+ assert state != null && Display.findDisplay(Thread.currentThread()) != null;
+
+ // 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)) {
+ // Avoid multiple decorations of the closed state
+ if (!TERMINAL_TITLE_TERMINATED_PATTERN.matcher(oldTitle).matches()) {
+ newTitle = NLS.bind(Messages.TabTerminalListener_consoleTerminated, oldTitle);
+ } else {
+ newTitle = oldTitle;
+ }
+ }
+
+ 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) {
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java
new file mode 100644
index 000000000..29445d972
--- /dev/null
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.terminals/src/org/eclipse/tm/te/ui/terminals/view/TerminalsView.java
@@ -0,0 +1,309 @@
+/*******************************************************************************
+ * Copyright (c) 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 v1.0 which accompanies this distribution, and is
+ * available at http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Wind River Systems - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.tm.te.ui.terminals.view;
+
+import org.eclipse.core.runtime.Assert;
+import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.custom.CTabFolder;
+import org.eclipse.swt.graphics.Color;
+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.te.ui.terminals.interfaces.ITerminalsView;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderManager;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderMenuHandler;
+import org.eclipse.tm.te.ui.terminals.tabs.TabFolderToolbarHandler;
+import org.eclipse.ui.IWorkbenchPreferenceConstants;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.part.PageBook;
+import org.eclipse.ui.part.ViewPart;
+
+/**
+ * Terminals view.
+ */
+public class TerminalsView extends ViewPart implements ITerminalsView {
+
+ // Reference to the main page book control
+ private PageBook pageBookControl;
+ // Reference to the tab folder maintaining the consoles
+ private CTabFolder tabFolderControl;
+ // Reference to the tab folder manager
+ private 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;
+
+ /**
+ * Constructor.
+ */
+ public TerminalsView() {
+ super();
+ }
+
+ /* (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.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();
+ }
+
+ /**
+ * Creates the {@link PageBook} instance.
+ *
+ * @param parent The parent composite. Must not be <code>null</code>.
+ * @return The page book instance. Must never be <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ 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 terminal console view instance.
+ * <p>
+ * <b>Note:</b> The default implementation returns the view id as context help id.
+ *
+ * @return The context help id or <code>null</code> 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 <code>null</code>.
+ * @return The empty page control instance. Must never be <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ protected void doConfigureEmptyPageControl(Control control) {
+ Assert.isNotNull(control);
+ }
+
+ /**
+ * Creates the tab folder control instance.
+ *
+ * @param parent The parent composite. Must not be <code>null</code>.
+ * @return The tab folder control instance. Must never be <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ protected void doConfigureTabFolderControl(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));
+ }
+
+ /**
+ * If <code>True</code> is returned, the inner tabs are colored with
+ * gradient coloring set in the Eclipse workbench color settings.
+ *
+ * @return <code>True</code> to use gradient tab colors, <code>false</code> otherwise.
+ */
+ protected boolean useGradientTabBackgroundColor() {
+ return false;
+ }
+
+ /**
+ * Creates the tab folder manager.
+ *
+ * @param parentView The parent view instance. Must be not <code>null</code>.
+ * @return The tab folder manager. Must never be <code>null</code>.
+ */
+ 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 be not <code>null</code>.
+ * @return The tab folder menu handler. Must never be <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ protected void doConfigureTabFolderMenuHandler(TabFolderMenuHandler menuHandler) {
+ Assert.isNotNull(menuHandler);
+ menuHandler.initialize();
+ }
+
+ /**
+ * Creates the tab folder toolbar handler.
+ *
+ * @param parentView The parent view instance. Must be not <code>null</code>.
+ * @return The tab folder toolbar handler. Must never be <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ protected void doConfigureTabFolderToolbarHandler(TabFolderToolbarHandler toolbarHandler) {
+ Assert.isNotNull(toolbarHandler);
+ toolbarHandler.initialize();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
+ */
+ @Override
+ public void setFocus() {
+ pageBookControl.setFocus();
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView#switchToEmptyPageControl()
+ */
+ @Override
+ public void switchToEmptyPageControl() {
+ if (!pageBookControl.isDisposed() && !emptyPageControl.isDisposed()) pageBookControl.showPage(emptyPageControl);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.tm.te.ui.terminals.interfaces.ITerminalsView#switchToTabFolderControl()
+ */
+ @Override
+ public void switchToTabFolderControl() {
+ if (!pageBookControl.isDisposed() && !tabFolderControl.isDisposed()) pageBookControl.showPage(tabFolderControl);
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
+ */
+ @Override
+ public Object getAdapter(Class adapter) {
+ if (CTabFolder.class.isAssignableFrom(adapter)) {
+ return tabFolderControl;
+ } else if (TabFolderManager.class.isAssignableFrom(adapter)) {
+ return tabFolderManager;
+ } else if (TabFolderMenuHandler.class.isAssignableFrom(adapter)) {
+ return tabFolderMenuHandler;
+ } else if (TabFolderToolbarHandler.class.isAssignableFrom(adapter)) {
+ return tabFolderToolbarHandler;
+ }
+
+ return super.getAdapter(adapter);
+ }
+}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/activator/UIPlugin.java
index 930f47896..49587c040 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/activator/UIPlugin.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/activator/UIPlugin.java
@@ -92,7 +92,7 @@ public class UIPlugin extends AbstractUIPlugin {
@Override
protected void initializeImageRegistry(ImageRegistry registry) {
URL url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_EVIEW + "prop_ps.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_EDITOR, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.EDITOR, ImageDescriptor.createFromURL(url));
}
/**
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/interfaces/ImageConsts.java b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/interfaces/ImageConsts.java
index bc7c5fedb..1b63845dc 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/interfaces/ImageConsts.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/interfaces/ImageConsts.java
@@ -28,5 +28,5 @@ public interface ImageConsts {
/**
* The key to access the Target Explorer editor image.
*/
- public static final String IMAGE_EDITOR = "TargetExplorerEditor"; //$NON-NLS-1$
+ public static final String EDITOR = "TargetExplorerEditor"; //$NON-NLS-1$
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/actions/NewActionProvider.java b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/actions/NewActionProvider.java
index 6aa9cc4fa..377f846e3 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/actions/NewActionProvider.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/actions/NewActionProvider.java
@@ -59,8 +59,8 @@ public class NewActionProvider extends CommonActionProvider {
window.getWorkbench().getHelpSystem().setHelp(newWizardCommandAction, IContextHelpIds.NEW_TARGET_WIZARD);
newWizardCommandActionToolbar = new CommandAction(window, "org.eclipse.tm.te.ui.command.newWizards"); //$NON-NLS-1$
- newWizardCommandActionToolbar.setImageDescriptor(org.eclipse.tm.te.ui.activator.UIPlugin.getImageDescriptor(ImageConsts.IMAGE_NEW_TARGET_WIZARD_ENABLED));
- newWizardCommandActionToolbar.setDisabledImageDescriptor(org.eclipse.tm.te.ui.activator.UIPlugin.getImageDescriptor(ImageConsts.IMAGE_NEW_TARGET_WIZARD_DISABLED));
+ newWizardCommandActionToolbar.setImageDescriptor(org.eclipse.tm.te.ui.activator.UIPlugin.getImageDescriptor(ImageConsts.NEW_TARGET_WIZARD_ENABLED));
+ newWizardCommandActionToolbar.setDisabledImageDescriptor(org.eclipse.tm.te.ui.activator.UIPlugin.getImageDescriptor(ImageConsts.NEW_TARGET_WIZARD_DISABLED));
newWizardCommandActionToolbar.setText(Messages.NewActionProvider_NewWizardCommandAction_label);
newWizardCommandActionToolbar.setToolTipText(Messages.NewActionProvider_NewWizardCommandAction_tooltip);
window.getWorkbench().getHelpSystem().setHelp(newWizardCommandActionToolbar, IContextHelpIds.NEW_TARGET_WIZARD);
@@ -100,7 +100,7 @@ public class NewActionProvider extends CommonActionProvider {
// Create the new sub menu
IMenuManager newMenu = new MenuManager(Messages.NewActionProvider_NewMenu_label,
- org.eclipse.tm.te.ui.activator.UIPlugin.getImageDescriptor(ImageConsts.IMAGE_NEW_TARGET_WIZARD_ENABLED),
+ org.eclipse.tm.te.ui.activator.UIPlugin.getImageDescriptor(ImageConsts.NEW_TARGET_WIZARD_ENABLED),
IUIConstants.ID_EXPLORER + ".menu.new"); //$NON-NLS-1$
// Add the context sensitive wizards (commonWizard element)
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/editor/EditorInput.java b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/editor/EditorInput.java
index cdaf7c9ed..c2e4ee166 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/editor/EditorInput.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui.views/src/org/eclipse/tm/te/ui/views/internal/editor/EditorInput.java
@@ -92,7 +92,7 @@ public class EditorInput implements IEditorInput, IPersistableElement {
*/
@Override
public ImageDescriptor getImageDescriptor() {
- return UIPlugin.getImageDescriptor(ImageConsts.IMAGE_EDITOR);
+ return UIPlugin.getImageDescriptor(ImageConsts.EDITOR);
}
/* (non-Javadoc)
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.properties b/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.properties
index 02a60ccf5..a5feb20aa 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.properties
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.properties
@@ -28,4 +28,4 @@ Command.newWizards.description=Open the New target wizard
# ***** Executors / Executor Utility Delegates *****
-EclipsePlatformDisplayExecutorUtilDelegate.label=Eclipse Platform Display Executor Utility Delegate
+SWTDisplayExecutorUtilDelegate.label=SWT Display Executor Utility Delegate
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.xml b/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.xml
index 5fde8f5d2..3254da5df 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.xml
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/plugin.xml
@@ -60,18 +60,18 @@
<!-- Executor service contributions -->
<extension point="org.eclipse.tm.te.runtime.concurrent.executorServices">
<executorService
- id="org.eclipse.tm.te.ui.executors.platform.display"
+ id="org.eclipse.tm.te.ui.executors.SWTDisplay"
label="Eclipse Platform Display Executor"
- class="org.eclipse.tm.te.ui.internal.executors.EclipsePlatformDisplayExecutor">
+ class="org.eclipse.tm.te.ui.internal.executors.SWTDisplayExecutor">
</executorService>
</extension>
<!-- Executor utility delegate contributions -->
<extension point="org.eclipse.tm.te.runtime.concurrent.executorUtilDelegates">
<executorUtilDelegate
- class="org.eclipse.tm.te.ui.internal.executors.EclipsePlatformDisplayExecutorUtilDelegate"
- id="org.eclipse.tm.te.ui.executors.delegate.display"
- label="%EclipsePlatformDisplayExecutorUtilDelegate.label">
+ class="org.eclipse.tm.te.ui.internal.executors.SWTDisplayExecutorUtilDelegate"
+ id="org.eclipse.tm.te.ui.executors.delegate.SWTDisplay"
+ label="%SWTDisplayExecutorUtilDelegate.label">
</executorUtilDelegate>
</extension>
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/activator/UIPlugin.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/activator/UIPlugin.java
index 27427ba60..4705b207c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/activator/UIPlugin.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/activator/UIPlugin.java
@@ -89,13 +89,13 @@ public class UIPlugin extends AbstractUIPlugin {
@Override
protected void initializeImageRegistry(ImageRegistry registry) {
URL url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_WIZBAN + "newtarget_wiz.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_NEW_TARGET_WIZARD, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.NEW_TARGET_WIZARD, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_DLCL + "newtarget_wiz.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_NEW_TARGET_WIZARD_DISABLED, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.NEW_TARGET_WIZARD_DISABLED, ImageDescriptor.createFromURL(url));
url = UIPlugin.getDefault().getBundle().getEntry(ImageConsts.IMAGE_DIR_ROOT + ImageConsts.IMAGE_DIR_ELCL + "newtarget_wiz.gif"); //$NON-NLS-1$
- registry.put(ImageConsts.IMAGE_NEW_TARGET_WIZARD_ENABLED, ImageDescriptor.createFromURL(url));
+ registry.put(ImageConsts.NEW_TARGET_WIZARD_ENABLED, ImageDescriptor.createFromURL(url));
}
/**
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java
index d5170d922..9ac6f85f5 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/IUIConstants.java
@@ -13,8 +13,6 @@ import org.eclipse.tm.te.ui.activator.UIPlugin;
/**
* Target Explorer: Common UI constants.
- *
- * @author uwe.stieber@windriver.com
*/
public interface IUIConstants {
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/ImageConsts.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/ImageConsts.java
index edd7a7036..55619f7d1 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/ImageConsts.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/interfaces/ImageConsts.java
@@ -40,15 +40,15 @@ public interface ImageConsts {
/**
* The key to access the New target wizard banner image.
*/
- public static final String IMAGE_NEW_TARGET_WIZARD = "NewTargetWizard"; //$NON-NLS-1$
+ public static final String NEW_TARGET_WIZARD = "NewTargetWizard"; //$NON-NLS-1$
/**
* The key to access the New target wizard image (enabled).
*/
- public static final String IMAGE_NEW_TARGET_WIZARD_ENABLED = "NewTargetWizard_enabled"; //$NON-NLS-1$
+ public static final String NEW_TARGET_WIZARD_ENABLED = "NewTargetWizard_enabled"; //$NON-NLS-1$
/**
* The key to access the New target wizard image (disabled).
*/
- public static final String IMAGE_NEW_TARGET_WIZARD_DISABLED = "NewTargetWizard_disabled"; //$NON-NLS-1$
+ public static final String NEW_TARGET_WIZARD_DISABLED = "NewTargetWizard_disabled"; //$NON-NLS-1$
}
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/EclipsePlatformDisplayExecutor.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/SWTDisplayExecutor.java
index dcfb218f0..120421a4c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/EclipsePlatformDisplayExecutor.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/SWTDisplayExecutor.java
@@ -18,28 +18,29 @@ import org.eclipse.tm.te.ui.activator.UIPlugin;
import org.eclipse.ui.PlatformUI;
/**
- * Eclipse platform display executor implementation utilizing the platform display.
+ * SWT display executor implementation utilizing the platform display.
*/
-public class EclipsePlatformDisplayExecutor extends ExecutableExtension implements IExecutor, ISingleThreadedExecutor, INestableExecutor {
+public class SWTDisplayExecutor extends ExecutableExtension implements IExecutor, ISingleThreadedExecutor, INestableExecutor {
/* (non-Javadoc)
* @see java.util.concurrent.Executor#execute(java.lang.Runnable)
*/
@Override
public void execute(Runnable command) {
- // In case we do have a display, just execute the runnable asynchronously using this display
- if (PlatformUI.isWorkbenchRunning() &&
- PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getDisplay() != null) {
+ // Try the platform display first
+ if (PlatformUI.isWorkbenchRunning()
+ && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getDisplay() != null
+ && !PlatformUI.getWorkbench().getDisplay().isDisposed()) {
PlatformUI.getWorkbench().getDisplay().asyncExec(command);
} else {
- // Check if the current thread is the display thread
+ // Fallback to the display associated with the current thread
Display display = Display.findDisplay(Thread.currentThread());
- // if we got the display for the riverbed dispatch thread, we can execute the
- // original runnable now
- if (display != null) {
+ // If there is a display associated with the current thread,
+ // execute the runnable using that display instance.
+ if (display != null && !display.isDisposed()) {
display.asyncExec(command);
} else {
- // Well, we don't have any display to execute the runnable at.
+ // There is no display to execute the runnable at.
// Drop execution and write a trace message if enabled
UIPlugin.getTraceHandler().trace("DROPPED display command invocation. No display instance found.!", 1, this); //$NON-NLS-1$
}
@@ -60,9 +61,16 @@ public class EclipsePlatformDisplayExecutor extends ExecutableExtension implemen
@Override
public boolean isExecutorThread(Thread thread) {
if (thread != null) {
- // Find the display for this thread
+ // Try the platform display first
+ if (PlatformUI.isWorkbenchRunning()
+ && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getDisplay() != null
+ && !PlatformUI.getWorkbench().getDisplay().isDisposed()) {
+ return thread.equals(PlatformUI.getWorkbench().getDisplay().getThread());
+ }
+
+ // Fallback to the display associated with the current thread
Display display = Display.findDisplay(thread);
- if (display != null) {
+ if (display != null && !display.isDisposed()) {
return thread.equals(display.getThread());
}
}
@@ -82,8 +90,16 @@ public class EclipsePlatformDisplayExecutor extends ExecutableExtension implemen
*/
@Override
public boolean readAndExecute() {
+ // Try the platform display first
+ if (PlatformUI.isWorkbenchRunning()
+ && PlatformUI.getWorkbench() != null && PlatformUI.getWorkbench().getDisplay() != null
+ && !PlatformUI.getWorkbench().getDisplay().isDisposed()) {
+ return PlatformUI.getWorkbench().getDisplay().readAndDispatch();
+ }
+
+ // Fallback to the display associated with the current thread
Display display = Display.getCurrent();
- if (display != null) {
+ if (display != null && !display.isDisposed()) {
return display.readAndDispatch();
}
return false;
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/EclipsePlatformDisplayExecutorUtilDelegate.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/SWTDisplayExecutorUtilDelegate.java
index 48e51779e..d456aa42c 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/EclipsePlatformDisplayExecutorUtilDelegate.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/internal/executors/SWTDisplayExecutorUtilDelegate.java
@@ -14,9 +14,9 @@ import org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutorUtilDelegate;
import org.eclipse.tm.te.runtime.extensions.ExecutableExtension;
/**
- * Eclipse platform display executor utility delegate implementation.
+ * SWT display executor utility delegate implementation.
*/
-public class EclipsePlatformDisplayExecutorUtilDelegate extends ExecutableExtension implements IExecutorUtilDelegate {
+public class SWTDisplayExecutorUtilDelegate extends ExecutableExtension implements IExecutorUtilDelegate {
/* (non-Javadoc)
* @see org.eclipse.tm.te.runtime.concurrent.interfaces.IExecutorUtilDelegate#isHandledExecutorThread()
diff --git a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/wizards/newWizard/NewWizard.java b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/wizards/newWizard/NewWizard.java
index f79157a5a..dd7fecef3 100644
--- a/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/wizards/newWizard/NewWizard.java
+++ b/target_explorer/plugins/org.eclipse.tm.te.ui/src/org/eclipse/tm/te/ui/wizards/newWizard/NewWizard.java
@@ -64,7 +64,7 @@ public final class NewWizard extends Wizard implements INewWizard {
*/
@Override
public Image getDefaultPageImage() {
- return UIPlugin.getImage(ImageConsts.IMAGE_NEW_TARGET_WIZARD);
+ return UIPlugin.getImage(ImageConsts.NEW_TARGET_WIZARD);
}

Back to the top